Into the woods
This commit is contained in:
parent
7b712ac68f
commit
0aabb19a45
16 changed files with 2263 additions and 2258 deletions
|
@ -35,7 +35,7 @@ git = { path = "../git" }
|
|||
gpui = { package = "gpui2", path = "../gpui2" }
|
||||
language = { package = "language2", path = "../language2" }
|
||||
lsp = { package = "lsp2", path = "../lsp2" }
|
||||
multi_buffer = { path = "../multi_buffer" }
|
||||
multi_buffer = { package = "multi_buffer2", path = "../multi_buffer2" }
|
||||
project = { package = "project2", path = "../project2" }
|
||||
rpc = { package = "rpc2", path = "../rpc2" }
|
||||
rich_text = { path = "../rich_text" }
|
||||
|
@ -80,7 +80,7 @@ util = { path = "../util", features = ["test-support"] }
|
|||
project = { package = "project2", path = "../project2", features = ["test-support"] }
|
||||
settings = { package = "settings2", path = "../settings2", features = ["test-support"] }
|
||||
workspace = { package = "workspace2", path = "../workspace2", features = ["test-support"] }
|
||||
multi_buffer = { path = "../multi_buffer", features = ["test-support"] }
|
||||
multi_buffer = { package = "multi_buffer2", path = "../multi_buffer2", features = ["test-support"] }
|
||||
|
||||
ctor.workspace = true
|
||||
env_logger.workspace = true
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::EditorSettings;
|
||||
use gpui::{Entity, ModelContext};
|
||||
use gpui::ModelContext;
|
||||
use settings::Settings;
|
||||
use settings::SettingsStore;
|
||||
use smol::Timer;
|
||||
use std::time::Duration;
|
||||
|
@ -16,7 +17,7 @@ pub struct BlinkManager {
|
|||
impl BlinkManager {
|
||||
pub fn new(blink_interval: Duration, cx: &mut ModelContext<Self>) -> Self {
|
||||
// Make sure we blink the cursors if the setting is re-enabled
|
||||
cx.observe_global::<SettingsStore, _>(move |this, cx| {
|
||||
cx.observe_global::<SettingsStore>(move |this, cx| {
|
||||
this.blink_cursors(this.blink_epoch, cx)
|
||||
})
|
||||
.detach();
|
||||
|
@ -41,14 +42,9 @@ impl BlinkManager {
|
|||
|
||||
let epoch = self.next_blink_epoch();
|
||||
let interval = self.blink_interval;
|
||||
cx.spawn(|this, mut cx| {
|
||||
let this = this.downgrade();
|
||||
async move {
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
Timer::after(interval).await;
|
||||
if let Some(this) = this.upgrade(&cx) {
|
||||
this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
@ -68,14 +64,11 @@ impl BlinkManager {
|
|||
|
||||
let epoch = self.next_blink_epoch();
|
||||
let interval = self.blink_interval;
|
||||
cx.spawn(|this, mut cx| {
|
||||
let this = this.downgrade();
|
||||
async move {
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
Timer::after(interval).await;
|
||||
if let Some(this) = this.upgrade(&cx) {
|
||||
if let Some(this) = this.upgrade() {
|
||||
this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
|
|
@ -497,62 +497,63 @@ impl DisplaySnapshot {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn highlighted_chunks<'a>(
|
||||
&'a self,
|
||||
display_rows: Range<u32>,
|
||||
language_aware: bool,
|
||||
style: &'a EditorStyle,
|
||||
) -> impl Iterator<Item = HighlightedChunk<'a>> {
|
||||
self.chunks(
|
||||
display_rows,
|
||||
language_aware,
|
||||
Some(style.theme.hint),
|
||||
Some(style.theme.suggestion),
|
||||
)
|
||||
.map(|chunk| {
|
||||
let mut highlight_style = chunk
|
||||
.syntax_highlight_id
|
||||
.and_then(|id| id.style(&style.syntax));
|
||||
// pub fn highlighted_chunks<'a>(
|
||||
// &'a self,
|
||||
// display_rows: Range<u32>,
|
||||
// language_aware: bool,
|
||||
// style: &'a EditorStyle,
|
||||
// ) -> impl Iterator<Item = HighlightedChunk<'a>> {
|
||||
// self.chunks(
|
||||
// display_rows,
|
||||
// language_aware,
|
||||
// Some(style.theme.hint),
|
||||
// Some(style.theme.suggestion),
|
||||
// )
|
||||
// .map(|chunk| {
|
||||
// let mut highlight_style = chunk
|
||||
// .syntax_highlight_id
|
||||
// .and_then(|id| id.style(&style.syntax));
|
||||
|
||||
if let Some(chunk_highlight) = chunk.highlight_style {
|
||||
if let Some(highlight_style) = highlight_style.as_mut() {
|
||||
highlight_style.highlight(chunk_highlight);
|
||||
} else {
|
||||
highlight_style = Some(chunk_highlight);
|
||||
}
|
||||
}
|
||||
// if let Some(chunk_highlight) = chunk.highlight_style {
|
||||
// if let Some(highlight_style) = highlight_style.as_mut() {
|
||||
// highlight_style.highlight(chunk_highlight);
|
||||
// } else {
|
||||
// highlight_style = Some(chunk_highlight);
|
||||
// }
|
||||
// }
|
||||
|
||||
let mut diagnostic_highlight = HighlightStyle::default();
|
||||
// let mut diagnostic_highlight = HighlightStyle::default();
|
||||
|
||||
if chunk.is_unnecessary {
|
||||
diagnostic_highlight.fade_out = Some(style.unnecessary_code_fade);
|
||||
}
|
||||
// if chunk.is_unnecessary {
|
||||
// diagnostic_highlight.fade_out = Some(style.unnecessary_code_fade);
|
||||
// }
|
||||
|
||||
if let Some(severity) = chunk.diagnostic_severity {
|
||||
// Omit underlines for HINT/INFO diagnostics on 'unnecessary' code.
|
||||
if severity <= DiagnosticSeverity::WARNING || !chunk.is_unnecessary {
|
||||
let diagnostic_style = super::diagnostic_style(severity, true, style);
|
||||
diagnostic_highlight.underline = Some(UnderlineStyle {
|
||||
color: Some(diagnostic_style.message.text.color),
|
||||
thickness: 1.0.into(),
|
||||
wavy: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
// if let Some(severity) = chunk.diagnostic_severity {
|
||||
// // Omit underlines for HINT/INFO diagnostics on 'unnecessary' code.
|
||||
// if severity <= DiagnosticSeverity::WARNING || !chunk.is_unnecessary {
|
||||
// todo!()
|
||||
// // let diagnostic_style = super::diagnostic_style(severity, true, style);
|
||||
// // diagnostic_highlight.underline = Some(UnderlineStyle {
|
||||
// // color: Some(diagnostic_style.message.text.color),
|
||||
// // thickness: 1.0.into(),
|
||||
// // wavy: true,
|
||||
// // });
|
||||
// }
|
||||
// }
|
||||
|
||||
if let Some(highlight_style) = highlight_style.as_mut() {
|
||||
highlight_style.highlight(diagnostic_highlight);
|
||||
} else {
|
||||
highlight_style = Some(diagnostic_highlight);
|
||||
}
|
||||
// if let Some(highlight_style) = highlight_style.as_mut() {
|
||||
// highlight_style.highlight(diagnostic_highlight);
|
||||
// } else {
|
||||
// highlight_style = Some(diagnostic_highlight);
|
||||
// }
|
||||
|
||||
HighlightedChunk {
|
||||
chunk: chunk.text,
|
||||
style: highlight_style,
|
||||
is_tab: chunk.is_tab,
|
||||
}
|
||||
})
|
||||
}
|
||||
// HighlightedChunk {
|
||||
// chunk: chunk.text,
|
||||
// style: highlight_style,
|
||||
// is_tab: chunk.is_tab,
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
pub fn lay_out_line_for_row(
|
||||
&self,
|
||||
|
@ -606,7 +607,7 @@ impl DisplaySnapshot {
|
|||
// });
|
||||
}
|
||||
|
||||
text_layout_cache.layout_text(&line, editor_style.text.font_size, &styles)
|
||||
text_layout_cache.layout_text(&line, editor_style.text.font_size, &styles, None)
|
||||
}
|
||||
|
||||
pub fn x_for_point(
|
||||
|
|
|
@ -932,15 +932,15 @@ impl BlockDisposition {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c> Deref for BlockContext<'a, 'b, 'c> {
|
||||
type Target = ViewContext<'a, 'b, Editor>;
|
||||
impl<'a> Deref for BlockContext<'a, '_> {
|
||||
type Target = ViewContext<'a, Editor>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.view_context
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for BlockContext<'_, '_, '_> {
|
||||
impl DerefMut for BlockContext<'_, '_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.view_context
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use super::{
|
|||
Highlights,
|
||||
};
|
||||
use crate::MultiBufferSnapshot;
|
||||
use gpui::{AppContext, FontId, Model, ModelContext, Pixels, Task};
|
||||
use gpui::{AppContext, FontId, LineWrapper, Model, ModelContext, Pixels, Task};
|
||||
use language::{Chunk, Point};
|
||||
use lazy_static::lazy_static;
|
||||
use smol::future::yield_now;
|
||||
|
@ -20,7 +20,7 @@ pub struct WrapMap {
|
|||
pending_edits: VecDeque<(TabSnapshot, Vec<TabEdit>)>,
|
||||
interpolated_edits: Patch<u32>,
|
||||
edits_since_sync: Patch<u32>,
|
||||
wrap_width: Option<f32>,
|
||||
wrap_width: Option<Pixels>,
|
||||
background_task: Option<Task<()>>,
|
||||
font: (FontId, Pixels),
|
||||
}
|
||||
|
@ -130,7 +130,11 @@ impl WrapMap {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_wrap_width(&mut self, wrap_width: Option<f32>, cx: &mut ModelContext<Self>) -> bool {
|
||||
pub fn set_wrap_width(
|
||||
&mut self,
|
||||
wrap_width: Option<Pixels>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> bool {
|
||||
if wrap_width == self.wrap_width {
|
||||
return false;
|
||||
}
|
||||
|
@ -379,7 +383,7 @@ impl WrapSnapshot {
|
|||
&mut self,
|
||||
new_tab_snapshot: TabSnapshot,
|
||||
tab_edits: &[TabEdit],
|
||||
wrap_width: f32,
|
||||
wrap_width: Pixels,
|
||||
line_wrapper: &mut LineWrapper,
|
||||
) -> Patch<u32> {
|
||||
#[derive(Debug)]
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
use gpui::Settings;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::Settings;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct EditorSettings {
|
||||
|
@ -55,7 +55,7 @@ impl Settings for EditorSettings {
|
|||
fn load(
|
||||
default_value: &Self::FileContent,
|
||||
user_values: &[&Self::FileContent],
|
||||
_: &gpui::AppContext,
|
||||
_: &mut gpui::AppContext,
|
||||
) -> anyhow::Result<Self> {
|
||||
Self::load_via_json_merge(default_value, user_values)
|
||||
}
|
||||
|
|
|
@ -3,9 +3,11 @@ use super::{
|
|||
};
|
||||
use crate::{
|
||||
display_map::{BlockStyle, DisplaySnapshot},
|
||||
mouse_context_menu, EditorSettings, EditorStyle, GutterHover, UnfoldAt,
|
||||
EditorStyle,
|
||||
};
|
||||
use gpui::{
|
||||
px, relative, AnyElement, Bounds, Element, Hsla, Line, Pixels, Size, Style, TextRun, TextSystem,
|
||||
};
|
||||
use gpui::{AnyElement, Bounds, Element, Hsla, Line, Pixels, Size, Style, TextRun, TextSystem};
|
||||
use language::{CursorShape, Selection};
|
||||
use std::{ops::Range, sync::Arc};
|
||||
use sum_tree::Bias;
|
||||
|
@ -1997,7 +1999,10 @@ impl Element<Editor> for EditorElement {
|
|||
element_state: &mut Self::ElementState,
|
||||
cx: &mut gpui::ViewContext<Editor>,
|
||||
) -> gpui::LayoutId {
|
||||
cx.request_layout(Style::default().size_full(), None)
|
||||
let mut style = Style::default();
|
||||
style.size.width = relative(1.).into();
|
||||
style.size.height = relative(1.).into();
|
||||
cx.request_layout(&style, None)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
|
@ -2011,13 +2016,8 @@ impl Element<Editor> for EditorElement {
|
|||
|
||||
let layout_text = cx.text_system().layout_text(
|
||||
"hello world",
|
||||
text_style.font_size,
|
||||
&[TextRun {
|
||||
len: "hello world".len(),
|
||||
font: text_style.font,
|
||||
color: text_style.color,
|
||||
underline: text_style.underline,
|
||||
}],
|
||||
text_style.font_size * cx.rem_size(),
|
||||
&[text_style.to_run("hello world".len())],
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
@ -2697,19 +2697,19 @@ impl PositionMap {
|
|||
position: gpui::Point<Pixels>,
|
||||
) -> PointForPosition {
|
||||
let scroll_position = self.snapshot.scroll_position();
|
||||
let position = position - text_bounds.origin();
|
||||
let y = position.y().max(0.0).min(self.size.y());
|
||||
let x = position.x() + (scroll_position.x() * self.em_width);
|
||||
let row = (y / self.line_height + scroll_position.y()) as u32;
|
||||
let position = position - text_bounds.origin;
|
||||
let y = position.y.max(px(0.)).min(self.size.width);
|
||||
let x = position.x + (scroll_position.x * self.em_width);
|
||||
let row = (y / self.line_height + scroll_position.y).into();
|
||||
let (column, x_overshoot_after_line_end) = if let Some(line) = self
|
||||
.line_layouts
|
||||
.get(row as usize - scroll_position.y() as usize)
|
||||
.get(row as usize - scroll_position.y.into())
|
||||
.map(|line_with_spaces| &line_with_spaces.line)
|
||||
{
|
||||
if let Some(ix) = line.index_for_x(x) {
|
||||
(ix as u32, 0.0)
|
||||
} else {
|
||||
(line.len() as u32, 0f32.max(x - line.width()))
|
||||
(line.len() as u32, px(0.).max(x - line.width()))
|
||||
}
|
||||
} else {
|
||||
(0, x)
|
||||
|
|
|
@ -466,35 +466,35 @@ pub struct InfoPopover {
|
|||
parsed_content: ParsedMarkdown,
|
||||
}
|
||||
|
||||
impl InfoPopover {
|
||||
pub fn render(
|
||||
&mut self,
|
||||
style: &EditorStyle,
|
||||
workspace: Option<WeakView<Workspace>>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> AnyElement<Editor> {
|
||||
MouseEventHandler::new::<InfoPopover, _>(0, cx, |_, cx| {
|
||||
Flex::column()
|
||||
.scrollable::<HoverBlock>(0, None, cx)
|
||||
.with_child(crate::render_parsed_markdown::<HoverBlock>(
|
||||
&self.parsed_content,
|
||||
style,
|
||||
workspace,
|
||||
cx,
|
||||
))
|
||||
.contained()
|
||||
.with_style(style.hover_popover.container)
|
||||
})
|
||||
.on_move(|_, _, _| {}) // Consume move events so they don't reach regions underneath.
|
||||
.with_cursor_style(CursorStyle::Arrow)
|
||||
.with_padding(Padding {
|
||||
bottom: HOVER_POPOVER_GAP,
|
||||
top: HOVER_POPOVER_GAP,
|
||||
..Default::default()
|
||||
})
|
||||
.into_any()
|
||||
}
|
||||
}
|
||||
// impl InfoPopover {
|
||||
// pub fn render(
|
||||
// &mut self,
|
||||
// style: &EditorStyle,
|
||||
// workspace: Option<WeakView<Workspace>>,
|
||||
// cx: &mut ViewContext<Editor>,
|
||||
// ) -> AnyElement<Editor> {
|
||||
// MouseEventHandler::new::<InfoPopover, _>(0, cx, |_, cx| {
|
||||
// Flex::column()
|
||||
// .scrollable::<HoverBlock>(0, None, cx)
|
||||
// .with_child(crate::render_parsed_markdown::<HoverBlock>(
|
||||
// &self.parsed_content,
|
||||
// style,
|
||||
// workspace,
|
||||
// cx,
|
||||
// ))
|
||||
// .contained()
|
||||
// .with_style(style.hover_popover.container)
|
||||
// })
|
||||
// .on_move(|_, _, _| {}) // Consume move events so they don't reach regions underneath.
|
||||
// .with_cursor_style(CursorStyle::Arrow)
|
||||
// .with_padding(Padding {
|
||||
// bottom: HOVER_POPOVER_GAP,
|
||||
// top: HOVER_POPOVER_GAP,
|
||||
// ..Default::default()
|
||||
// })
|
||||
// .into_any()
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DiagnosticPopover {
|
||||
|
|
|
@ -521,7 +521,7 @@ impl InlayHintCache {
|
|||
buffer_id: u64,
|
||||
excerpt_id: ExcerptId,
|
||||
id: InlayId,
|
||||
cx: &mut ViewContext<'_, '_, Editor>,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) {
|
||||
if let Some(excerpt_hints) = self.hints.get(&excerpt_id) {
|
||||
let mut guard = excerpt_hints.write();
|
||||
|
@ -582,7 +582,7 @@ fn spawn_new_update_tasks(
|
|||
excerpts_to_query: HashMap<ExcerptId, (Model<Buffer>, Global, Range<usize>)>,
|
||||
invalidate: InvalidationStrategy,
|
||||
update_cache_version: usize,
|
||||
cx: &mut ViewContext<'_, '_, Editor>,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) {
|
||||
let visible_hints = Arc::new(editor.visible_inlay_hints(cx));
|
||||
for (excerpt_id, (excerpt_buffer, new_task_buffer_version, excerpt_visible_range)) in
|
||||
|
@ -760,7 +760,7 @@ fn new_update_task(
|
|||
visible_hints: Arc<Vec<Inlay>>,
|
||||
cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
|
||||
lsp_request_limiter: Arc<Semaphore>,
|
||||
cx: &mut ViewContext<'_, '_, Editor>,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) -> Task<()> {
|
||||
cx.spawn(|editor, mut cx| async move {
|
||||
let closure_cx = cx.clone();
|
||||
|
@ -836,134 +836,134 @@ fn new_update_task(
|
|||
})
|
||||
}
|
||||
|
||||
async fn fetch_and_update_hints(
|
||||
editor: gpui::WeakView<Editor>,
|
||||
multi_buffer_snapshot: MultiBufferSnapshot,
|
||||
buffer_snapshot: BufferSnapshot,
|
||||
visible_hints: Arc<Vec<Inlay>>,
|
||||
cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
|
||||
query: ExcerptQuery,
|
||||
invalidate: bool,
|
||||
fetch_range: Range<language::Anchor>,
|
||||
lsp_request_limiter: Arc<Semaphore>,
|
||||
mut cx: gpui::AsyncAppContext,
|
||||
) -> anyhow::Result<()> {
|
||||
let (lsp_request_guard, got_throttled) = if query.invalidate.should_invalidate() {
|
||||
(None, false)
|
||||
} else {
|
||||
match lsp_request_limiter.try_acquire() {
|
||||
Some(guard) => (Some(guard), false),
|
||||
None => (Some(lsp_request_limiter.acquire().await), true),
|
||||
}
|
||||
};
|
||||
let fetch_range_to_log =
|
||||
fetch_range.start.to_point(&buffer_snapshot)..fetch_range.end.to_point(&buffer_snapshot);
|
||||
let inlay_hints_fetch_task = editor
|
||||
.update(&mut cx, |editor, cx| {
|
||||
if got_throttled {
|
||||
let query_not_around_visible_range = match editor.excerpt_visible_offsets(None, cx).remove(&query.excerpt_id) {
|
||||
Some((_, _, current_visible_range)) => {
|
||||
let visible_offset_length = current_visible_range.len();
|
||||
let double_visible_range = current_visible_range
|
||||
.start
|
||||
.saturating_sub(visible_offset_length)
|
||||
..current_visible_range
|
||||
.end
|
||||
.saturating_add(visible_offset_length)
|
||||
.min(buffer_snapshot.len());
|
||||
!double_visible_range
|
||||
.contains(&fetch_range.start.to_offset(&buffer_snapshot))
|
||||
&& !double_visible_range
|
||||
.contains(&fetch_range.end.to_offset(&buffer_snapshot))
|
||||
},
|
||||
None => true,
|
||||
};
|
||||
if query_not_around_visible_range {
|
||||
log::trace!("Fetching inlay hints for range {fetch_range_to_log:?} got throttled and fell off the current visible range, skipping.");
|
||||
if let Some(task_ranges) = editor
|
||||
.inlay_hint_cache
|
||||
.update_tasks
|
||||
.get_mut(&query.excerpt_id)
|
||||
{
|
||||
task_ranges.invalidate_range(&buffer_snapshot, &fetch_range);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
editor
|
||||
.buffer()
|
||||
.read(cx)
|
||||
.buffer(query.buffer_id)
|
||||
.and_then(|buffer| {
|
||||
let project = editor.project.as_ref()?;
|
||||
Some(project.update(cx, |project, cx| {
|
||||
project.inlay_hints(buffer, fetch_range.clone(), cx)
|
||||
}))
|
||||
})
|
||||
})
|
||||
.ok()
|
||||
.flatten();
|
||||
let new_hints = match inlay_hints_fetch_task {
|
||||
Some(fetch_task) => {
|
||||
log::debug!(
|
||||
"Fetching inlay hints for range {fetch_range_to_log:?}, reason: {query_reason}, invalidate: {invalidate}",
|
||||
query_reason = query.reason,
|
||||
);
|
||||
log::trace!(
|
||||
"Currently visible hints: {visible_hints:?}, cached hints present: {}",
|
||||
cached_excerpt_hints.is_some(),
|
||||
);
|
||||
fetch_task.await.context("inlay hint fetch task")?
|
||||
}
|
||||
None => return Ok(()),
|
||||
};
|
||||
drop(lsp_request_guard);
|
||||
log::debug!(
|
||||
"Fetched {} hints for range {fetch_range_to_log:?}",
|
||||
new_hints.len()
|
||||
);
|
||||
log::trace!("Fetched hints: {new_hints:?}");
|
||||
// async fn fetch_and_update_hints(
|
||||
// editor: gpui::WeakView<Editor>,
|
||||
// multi_buffer_snapshot: MultiBufferSnapshot,
|
||||
// buffer_snapshot: BufferSnapshot,
|
||||
// visible_hints: Arc<Vec<Inlay>>,
|
||||
// cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
|
||||
// query: ExcerptQuery,
|
||||
// invalidate: bool,
|
||||
// fetch_range: Range<language::Anchor>,
|
||||
// lsp_request_limiter: Arc<Semaphore>,
|
||||
// mut cx: gpui::AsyncAppContext,
|
||||
// ) -> anyhow::Result<()> {
|
||||
// let (lsp_request_guard, got_throttled) = if query.invalidate.should_invalidate() {
|
||||
// (None, false)
|
||||
// } else {
|
||||
// match lsp_request_limiter.try_acquire() {
|
||||
// Some(guard) => (Some(guard), false),
|
||||
// None => (Some(lsp_request_limiter.acquire().await), true),
|
||||
// }
|
||||
// };
|
||||
// let fetch_range_to_log =
|
||||
// fetch_range.start.to_point(&buffer_snapshot)..fetch_range.end.to_point(&buffer_snapshot);
|
||||
// let inlay_hints_fetch_task = editor
|
||||
// .update(&mut cx, |editor, cx| {
|
||||
// if got_throttled {
|
||||
// let query_not_around_visible_range = match editor.excerpt_visible_offsets(None, cx).remove(&query.excerpt_id) {
|
||||
// Some((_, _, current_visible_range)) => {
|
||||
// let visible_offset_length = current_visible_range.len();
|
||||
// let double_visible_range = current_visible_range
|
||||
// .start
|
||||
// .saturating_sub(visible_offset_length)
|
||||
// ..current_visible_range
|
||||
// .end
|
||||
// .saturating_add(visible_offset_length)
|
||||
// .min(buffer_snapshot.len());
|
||||
// !double_visible_range
|
||||
// .contains(&fetch_range.start.to_offset(&buffer_snapshot))
|
||||
// && !double_visible_range
|
||||
// .contains(&fetch_range.end.to_offset(&buffer_snapshot))
|
||||
// },
|
||||
// None => true,
|
||||
// };
|
||||
// if query_not_around_visible_range {
|
||||
// log::trace!("Fetching inlay hints for range {fetch_range_to_log:?} got throttled and fell off the current visible range, skipping.");
|
||||
// if let Some(task_ranges) = editor
|
||||
// .inlay_hint_cache
|
||||
// .update_tasks
|
||||
// .get_mut(&query.excerpt_id)
|
||||
// {
|
||||
// task_ranges.invalidate_range(&buffer_snapshot, &fetch_range);
|
||||
// }
|
||||
// return None;
|
||||
// }
|
||||
// }
|
||||
// editor
|
||||
// .buffer()
|
||||
// .read(cx)
|
||||
// .buffer(query.buffer_id)
|
||||
// .and_then(|buffer| {
|
||||
// let project = editor.project.as_ref()?;
|
||||
// Some(project.update(cx, |project, cx| {
|
||||
// project.inlay_hints(buffer, fetch_range.clone(), cx)
|
||||
// }))
|
||||
// })
|
||||
// })
|
||||
// .ok()
|
||||
// .flatten();
|
||||
// let new_hints = match inlay_hints_fetch_task {
|
||||
// Some(fetch_task) => {
|
||||
// log::debug!(
|
||||
// "Fetching inlay hints for range {fetch_range_to_log:?}, reason: {query_reason}, invalidate: {invalidate}",
|
||||
// query_reason = query.reason,
|
||||
// );
|
||||
// log::trace!(
|
||||
// "Currently visible hints: {visible_hints:?}, cached hints present: {}",
|
||||
// cached_excerpt_hints.is_some(),
|
||||
// );
|
||||
// fetch_task.await.context("inlay hint fetch task")?
|
||||
// }
|
||||
// None => return Ok(()),
|
||||
// };
|
||||
// drop(lsp_request_guard);
|
||||
// log::debug!(
|
||||
// "Fetched {} hints for range {fetch_range_to_log:?}",
|
||||
// new_hints.len()
|
||||
// );
|
||||
// log::trace!("Fetched hints: {new_hints:?}");
|
||||
|
||||
let background_task_buffer_snapshot = buffer_snapshot.clone();
|
||||
let backround_fetch_range = fetch_range.clone();
|
||||
let new_update = cx
|
||||
.background()
|
||||
.spawn(async move {
|
||||
calculate_hint_updates(
|
||||
query.excerpt_id,
|
||||
invalidate,
|
||||
backround_fetch_range,
|
||||
new_hints,
|
||||
&background_task_buffer_snapshot,
|
||||
cached_excerpt_hints,
|
||||
&visible_hints,
|
||||
)
|
||||
})
|
||||
.await;
|
||||
if let Some(new_update) = new_update {
|
||||
log::debug!(
|
||||
"Applying update for range {fetch_range_to_log:?}: remove from editor: {}, remove from cache: {}, add to cache: {}",
|
||||
new_update.remove_from_visible.len(),
|
||||
new_update.remove_from_cache.len(),
|
||||
new_update.add_to_cache.len()
|
||||
);
|
||||
log::trace!("New update: {new_update:?}");
|
||||
editor
|
||||
.update(&mut cx, |editor, cx| {
|
||||
apply_hint_update(
|
||||
editor,
|
||||
new_update,
|
||||
query,
|
||||
invalidate,
|
||||
buffer_snapshot,
|
||||
multi_buffer_snapshot,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
// let background_task_buffer_snapshot = buffer_snapshot.clone();
|
||||
// let backround_fetch_range = fetch_range.clone();
|
||||
// let new_update = cx
|
||||
// .background()
|
||||
// .spawn(async move {
|
||||
// calculate_hint_updates(
|
||||
// query.excerpt_id,
|
||||
// invalidate,
|
||||
// backround_fetch_range,
|
||||
// new_hints,
|
||||
// &background_task_buffer_snapshot,
|
||||
// cached_excerpt_hints,
|
||||
// &visible_hints,
|
||||
// )
|
||||
// })
|
||||
// .await;
|
||||
// if let Some(new_update) = new_update {
|
||||
// log::debug!(
|
||||
// "Applying update for range {fetch_range_to_log:?}: remove from editor: {}, remove from cache: {}, add to cache: {}",
|
||||
// new_update.remove_from_visible.len(),
|
||||
// new_update.remove_from_cache.len(),
|
||||
// new_update.add_to_cache.len()
|
||||
// );
|
||||
// log::trace!("New update: {new_update:?}");
|
||||
// editor
|
||||
// .update(&mut cx, |editor, cx| {
|
||||
// apply_hint_update(
|
||||
// editor,
|
||||
// new_update,
|
||||
// query,
|
||||
// invalidate,
|
||||
// buffer_snapshot,
|
||||
// multi_buffer_snapshot,
|
||||
// cx,
|
||||
// );
|
||||
// })
|
||||
// .ok();
|
||||
// }
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
fn calculate_hint_updates(
|
||||
excerpt_id: ExcerptId,
|
||||
|
@ -1071,7 +1071,7 @@ fn apply_hint_update(
|
|||
invalidate: bool,
|
||||
buffer_snapshot: BufferSnapshot,
|
||||
multi_buffer_snapshot: MultiBufferSnapshot,
|
||||
cx: &mut ViewContext<'_, '_, Editor>,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) {
|
||||
let cached_excerpt_hints = editor
|
||||
.inlay_hint_cache
|
||||
|
|
|
@ -7,8 +7,8 @@ use anyhow::{Context, Result};
|
|||
use collections::HashSet;
|
||||
use futures::future::try_join_all;
|
||||
use gpui::{
|
||||
point, AnyElement, AppContext, AsyncAppContext, Entity, Model, Pixels, Subscription, Task,
|
||||
View, ViewContext, WeakView,
|
||||
point, AnyElement, AppContext, AsyncAppContext, Entity, Model, Pixels, SharedString,
|
||||
Subscription, Task, View, ViewContext, WeakView,
|
||||
};
|
||||
use language::{
|
||||
proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point,
|
||||
|
@ -304,133 +304,133 @@ impl FollowableItem for Editor {
|
|||
}
|
||||
}
|
||||
|
||||
async fn update_editor_from_message(
|
||||
this: WeakView<Editor>,
|
||||
project: Model<Project>,
|
||||
message: proto::update_view::Editor,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<()> {
|
||||
// Open all of the buffers of which excerpts were added to the editor.
|
||||
let inserted_excerpt_buffer_ids = message
|
||||
.inserted_excerpts
|
||||
.iter()
|
||||
.filter_map(|insertion| Some(insertion.excerpt.as_ref()?.buffer_id))
|
||||
.collect::<HashSet<_>>();
|
||||
let inserted_excerpt_buffers = project.update(cx, |project, cx| {
|
||||
inserted_excerpt_buffer_ids
|
||||
.into_iter()
|
||||
.map(|id| project.open_buffer_by_id(id, cx))
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
let _inserted_excerpt_buffers = try_join_all(inserted_excerpt_buffers).await?;
|
||||
// async fn update_editor_from_message(
|
||||
// this: WeakView<Editor>,
|
||||
// project: Model<Project>,
|
||||
// message: proto::update_view::Editor,
|
||||
// cx: &mut AsyncAppContext,
|
||||
// ) -> Result<()> {
|
||||
// // Open all of the buffers of which excerpts were added to the editor.
|
||||
// let inserted_excerpt_buffer_ids = message
|
||||
// .inserted_excerpts
|
||||
// .iter()
|
||||
// .filter_map(|insertion| Some(insertion.excerpt.as_ref()?.buffer_id))
|
||||
// .collect::<HashSet<_>>();
|
||||
// let inserted_excerpt_buffers = project.update(cx, |project, cx| {
|
||||
// inserted_excerpt_buffer_ids
|
||||
// .into_iter()
|
||||
// .map(|id| project.open_buffer_by_id(id, cx))
|
||||
// .collect::<Vec<_>>()
|
||||
// })?;
|
||||
// let _inserted_excerpt_buffers = try_join_all(inserted_excerpt_buffers).await?;
|
||||
|
||||
// Update the editor's excerpts.
|
||||
this.update(cx, |editor, cx| {
|
||||
editor.buffer.update(cx, |multibuffer, cx| {
|
||||
let mut removed_excerpt_ids = message
|
||||
.deleted_excerpts
|
||||
.into_iter()
|
||||
.map(ExcerptId::from_proto)
|
||||
.collect::<Vec<_>>();
|
||||
removed_excerpt_ids.sort_by({
|
||||
let multibuffer = multibuffer.read(cx);
|
||||
move |a, b| a.cmp(&b, &multibuffer)
|
||||
});
|
||||
// // Update the editor's excerpts.
|
||||
// this.update(cx, |editor, cx| {
|
||||
// editor.buffer.update(cx, |multibuffer, cx| {
|
||||
// let mut removed_excerpt_ids = message
|
||||
// .deleted_excerpts
|
||||
// .into_iter()
|
||||
// .map(ExcerptId::from_proto)
|
||||
// .collect::<Vec<_>>();
|
||||
// removed_excerpt_ids.sort_by({
|
||||
// let multibuffer = multibuffer.read(cx);
|
||||
// move |a, b| a.cmp(&b, &multibuffer)
|
||||
// });
|
||||
|
||||
let mut insertions = message.inserted_excerpts.into_iter().peekable();
|
||||
while let Some(insertion) = insertions.next() {
|
||||
let Some(excerpt) = insertion.excerpt else {
|
||||
continue;
|
||||
};
|
||||
let Some(previous_excerpt_id) = insertion.previous_excerpt_id else {
|
||||
continue;
|
||||
};
|
||||
let buffer_id = excerpt.buffer_id;
|
||||
let Some(buffer) = project.read(cx).buffer_for_id(buffer_id) else {
|
||||
continue;
|
||||
};
|
||||
// let mut insertions = message.inserted_excerpts.into_iter().peekable();
|
||||
// while let Some(insertion) = insertions.next() {
|
||||
// let Some(excerpt) = insertion.excerpt else {
|
||||
// continue;
|
||||
// };
|
||||
// let Some(previous_excerpt_id) = insertion.previous_excerpt_id else {
|
||||
// continue;
|
||||
// };
|
||||
// let buffer_id = excerpt.buffer_id;
|
||||
// let Some(buffer) = project.read(cx).buffer_for_id(buffer_id) else {
|
||||
// continue;
|
||||
// };
|
||||
|
||||
let adjacent_excerpts = iter::from_fn(|| {
|
||||
let insertion = insertions.peek()?;
|
||||
if insertion.previous_excerpt_id.is_none()
|
||||
&& insertion.excerpt.as_ref()?.buffer_id == buffer_id
|
||||
{
|
||||
insertions.next()?.excerpt
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
// let adjacent_excerpts = iter::from_fn(|| {
|
||||
// let insertion = insertions.peek()?;
|
||||
// if insertion.previous_excerpt_id.is_none()
|
||||
// && insertion.excerpt.as_ref()?.buffer_id == buffer_id
|
||||
// {
|
||||
// insertions.next()?.excerpt
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// });
|
||||
|
||||
multibuffer.insert_excerpts_with_ids_after(
|
||||
ExcerptId::from_proto(previous_excerpt_id),
|
||||
buffer,
|
||||
[excerpt]
|
||||
.into_iter()
|
||||
.chain(adjacent_excerpts)
|
||||
.filter_map(|excerpt| {
|
||||
Some((
|
||||
ExcerptId::from_proto(excerpt.id),
|
||||
deserialize_excerpt_range(excerpt)?,
|
||||
))
|
||||
}),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
// multibuffer.insert_excerpts_with_ids_after(
|
||||
// ExcerptId::from_proto(previous_excerpt_id),
|
||||
// buffer,
|
||||
// [excerpt]
|
||||
// .into_iter()
|
||||
// .chain(adjacent_excerpts)
|
||||
// .filter_map(|excerpt| {
|
||||
// Some((
|
||||
// ExcerptId::from_proto(excerpt.id),
|
||||
// deserialize_excerpt_range(excerpt)?,
|
||||
// ))
|
||||
// }),
|
||||
// cx,
|
||||
// );
|
||||
// }
|
||||
|
||||
multibuffer.remove_excerpts(removed_excerpt_ids, cx);
|
||||
});
|
||||
})?;
|
||||
// multibuffer.remove_excerpts(removed_excerpt_ids, cx);
|
||||
// });
|
||||
// })?;
|
||||
|
||||
// Deserialize the editor state.
|
||||
let (selections, pending_selection, scroll_top_anchor) = this.update(cx, |editor, cx| {
|
||||
let buffer = editor.buffer.read(cx).read(cx);
|
||||
let selections = message
|
||||
.selections
|
||||
.into_iter()
|
||||
.filter_map(|selection| deserialize_selection(&buffer, selection))
|
||||
.collect::<Vec<_>>();
|
||||
let pending_selection = message
|
||||
.pending_selection
|
||||
.and_then(|selection| deserialize_selection(&buffer, selection));
|
||||
let scroll_top_anchor = message
|
||||
.scroll_top_anchor
|
||||
.and_then(|anchor| deserialize_anchor(&buffer, anchor));
|
||||
anyhow::Ok((selections, pending_selection, scroll_top_anchor))
|
||||
})??;
|
||||
// // Deserialize the editor state.
|
||||
// let (selections, pending_selection, scroll_top_anchor) = this.update(cx, |editor, cx| {
|
||||
// let buffer = editor.buffer.read(cx).read(cx);
|
||||
// let selections = message
|
||||
// .selections
|
||||
// .into_iter()
|
||||
// .filter_map(|selection| deserialize_selection(&buffer, selection))
|
||||
// .collect::<Vec<_>>();
|
||||
// let pending_selection = message
|
||||
// .pending_selection
|
||||
// .and_then(|selection| deserialize_selection(&buffer, selection));
|
||||
// let scroll_top_anchor = message
|
||||
// .scroll_top_anchor
|
||||
// .and_then(|anchor| deserialize_anchor(&buffer, anchor));
|
||||
// anyhow::Ok((selections, pending_selection, scroll_top_anchor))
|
||||
// })??;
|
||||
|
||||
// Wait until the buffer has received all of the operations referenced by
|
||||
// the editor's new state.
|
||||
this.update(cx, |editor, cx| {
|
||||
editor.buffer.update(cx, |buffer, cx| {
|
||||
buffer.wait_for_anchors(
|
||||
selections
|
||||
.iter()
|
||||
.chain(pending_selection.as_ref())
|
||||
.flat_map(|selection| [selection.start, selection.end])
|
||||
.chain(scroll_top_anchor),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
})?
|
||||
.await?;
|
||||
// // Wait until the buffer has received all of the operations referenced by
|
||||
// // the editor's new state.
|
||||
// this.update(cx, |editor, cx| {
|
||||
// editor.buffer.update(cx, |buffer, cx| {
|
||||
// buffer.wait_for_anchors(
|
||||
// selections
|
||||
// .iter()
|
||||
// .chain(pending_selection.as_ref())
|
||||
// .flat_map(|selection| [selection.start, selection.end])
|
||||
// .chain(scroll_top_anchor),
|
||||
// cx,
|
||||
// )
|
||||
// })
|
||||
// })?
|
||||
// .await?;
|
||||
|
||||
// Update the editor's state.
|
||||
this.update(cx, |editor, cx| {
|
||||
if !selections.is_empty() || pending_selection.is_some() {
|
||||
editor.set_selections_from_remote(selections, pending_selection, cx);
|
||||
editor.request_autoscroll_remotely(Autoscroll::newest(), cx);
|
||||
} else if let Some(scroll_top_anchor) = scroll_top_anchor {
|
||||
editor.set_scroll_anchor_remote(
|
||||
ScrollAnchor {
|
||||
anchor: scroll_top_anchor,
|
||||
offset: point(message.scroll_x, message.scroll_y),
|
||||
},
|
||||
cx,
|
||||
);
|
||||
}
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
// // Update the editor's state.
|
||||
// this.update(cx, |editor, cx| {
|
||||
// if !selections.is_empty() || pending_selection.is_some() {
|
||||
// editor.set_selections_from_remote(selections, pending_selection, cx);
|
||||
// editor.request_autoscroll_remotely(Autoscroll::newest(), cx);
|
||||
// } else if let Some(scroll_top_anchor) = scroll_top_anchor {
|
||||
// editor.set_scroll_anchor_remote(
|
||||
// ScrollAnchor {
|
||||
// anchor: scroll_top_anchor,
|
||||
// offset: point(message.scroll_x, message.scroll_y),
|
||||
// },
|
||||
// cx,
|
||||
// );
|
||||
// }
|
||||
// })?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
fn serialize_excerpt(
|
||||
buffer_id: u64,
|
||||
|
@ -544,7 +544,7 @@ impl Item for Editor {
|
|||
}
|
||||
}
|
||||
|
||||
fn tab_tooltip_text(&self, cx: &AppContext) -> Option<Cow<str>> {
|
||||
fn tab_tooltip_text(&self, cx: &AppContext) -> Option<SharedString> {
|
||||
let file_path = self
|
||||
.buffer()
|
||||
.read(cx)
|
||||
|
@ -559,7 +559,7 @@ impl Item for Editor {
|
|||
Some(file_path.into())
|
||||
}
|
||||
|
||||
fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<Cow<str>> {
|
||||
fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<SharedString> {
|
||||
match path_for_buffer(&self.buffer, detail, true, cx)? {
|
||||
Cow::Borrowed(path) => Some(path.to_string_lossy()),
|
||||
Cow::Owned(path) => Some(path.to_string_lossy().to_string().into()),
|
||||
|
|
|
@ -168,7 +168,7 @@ pub fn update_inlay_link_and_hover_points(
|
|||
editor: &mut Editor,
|
||||
cmd_held: bool,
|
||||
shift_held: bool,
|
||||
cx: &mut ViewContext<'_, '_, Editor>,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) {
|
||||
let hovered_offset = if point_for_position.column_overshoot_after_line_end == 0 {
|
||||
Some(snapshot.display_point_to_inlay_offset(point_for_position.exact_unclipped, Bias::Left))
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
Anchor, DisplayPoint, Editor, EditorMode, Event, InlayHintRefreshReason, MultiBufferSnapshot,
|
||||
ToPoint,
|
||||
};
|
||||
use gpui::{point, AppContext, Pixels, Task, ViewContext};
|
||||
use gpui::{point, px, AppContext, Pixels, Styled, Task, ViewContext};
|
||||
use language::{Bias, Point};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
|
@ -44,7 +44,7 @@ impl ScrollAnchor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> Point<Pixels> {
|
||||
pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<Pixels> {
|
||||
let mut scroll_position = self.offset;
|
||||
if self.anchor != Anchor::min() {
|
||||
let scroll_top = self.anchor.to_display_point(snapshot).row() as f32;
|
||||
|
@ -80,13 +80,13 @@ impl OngoingScroll {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn filter(&self, delta: &mut Point<Pixels>) -> Option<Axis> {
|
||||
pub fn filter(&self, delta: &mut gpui::Point<Pixels>) -> Option<Axis> {
|
||||
const UNLOCK_PERCENT: f32 = 1.9;
|
||||
const UNLOCK_LOWER_BOUND: f32 = 6.;
|
||||
let mut axis = self.axis;
|
||||
|
||||
let x = delta.x().abs();
|
||||
let y = delta.y().abs();
|
||||
let x = delta.x.abs();
|
||||
let y = delta.y.abs();
|
||||
let duration = Instant::now().duration_since(self.last_event);
|
||||
if duration > SCROLL_EVENT_SEPARATION {
|
||||
//New ongoing scroll will start, determine axis
|
||||
|
@ -115,8 +115,12 @@ impl OngoingScroll {
|
|||
}
|
||||
|
||||
match axis {
|
||||
Some(Axis::Vertical) => *delta = point(0., delta.y()),
|
||||
Some(Axis::Horizontal) => *delta = point(delta.x(), 0.),
|
||||
Some(Axis::Vertical) => {
|
||||
*delta = point(pk(0.), delta.y());
|
||||
}
|
||||
Some(Axis::Horizontal) => {
|
||||
*delta = point(delta.x(), px(0.));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
|
@ -167,13 +171,13 @@ impl ScrollManager {
|
|||
self.ongoing.axis = axis;
|
||||
}
|
||||
|
||||
pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> Point<Pixels> {
|
||||
pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<Pixels> {
|
||||
self.anchor.scroll_position(snapshot)
|
||||
}
|
||||
|
||||
fn set_scroll_position(
|
||||
&mut self,
|
||||
scroll_position: Point<Pixels>,
|
||||
scroll_position: gpui::Point<Pixels>,
|
||||
map: &DisplaySnapshot,
|
||||
local: bool,
|
||||
autoscroll: bool,
|
||||
|
@ -282,160 +286,161 @@ impl ScrollManager {
|
|||
}
|
||||
}
|
||||
|
||||
impl Editor {
|
||||
pub fn vertical_scroll_margin(&mut self) -> usize {
|
||||
self.scroll_manager.vertical_scroll_margin as usize
|
||||
}
|
||||
// todo!()
|
||||
// impl Editor {
|
||||
// pub fn vertical_scroll_margin(&mut self) -> usize {
|
||||
// self.scroll_manager.vertical_scroll_margin as usize
|
||||
// }
|
||||
|
||||
pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut ViewContext<Self>) {
|
||||
self.scroll_manager.vertical_scroll_margin = margin_rows as f32;
|
||||
cx.notify();
|
||||
}
|
||||
// pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut ViewContext<Self>) {
|
||||
// self.scroll_manager.vertical_scroll_margin = margin_rows as f32;
|
||||
// cx.notify();
|
||||
// }
|
||||
|
||||
pub fn visible_line_count(&self) -> Option<f32> {
|
||||
self.scroll_manager.visible_line_count
|
||||
}
|
||||
// pub fn visible_line_count(&self) -> Option<f32> {
|
||||
// self.scroll_manager.visible_line_count
|
||||
// }
|
||||
|
||||
pub(crate) fn set_visible_line_count(&mut self, lines: f32, cx: &mut ViewContext<Self>) {
|
||||
let opened_first_time = self.scroll_manager.visible_line_count.is_none();
|
||||
self.scroll_manager.visible_line_count = Some(lines);
|
||||
if opened_first_time {
|
||||
cx.spawn(|editor, mut cx| async move {
|
||||
editor
|
||||
.update(&mut cx, |editor, cx| {
|
||||
editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx)
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.detach()
|
||||
}
|
||||
}
|
||||
// pub(crate) fn set_visible_line_count(&mut self, lines: f32, cx: &mut ViewContext<Self>) {
|
||||
// let opened_first_time = self.scroll_manager.visible_line_count.is_none();
|
||||
// self.scroll_manager.visible_line_count = Some(lines);
|
||||
// if opened_first_time {
|
||||
// cx.spawn(|editor, mut cx| async move {
|
||||
// editor
|
||||
// .update(&mut cx, |editor, cx| {
|
||||
// editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx)
|
||||
// })
|
||||
// .ok()
|
||||
// })
|
||||
// .detach()
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn set_scroll_position(
|
||||
&mut self,
|
||||
scroll_position: Point<Pixels>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.set_scroll_position_internal(scroll_position, true, false, cx);
|
||||
}
|
||||
// pub fn set_scroll_position(
|
||||
// &mut self,
|
||||
// scroll_position: gpui::Point<Pixels>,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) {
|
||||
// self.set_scroll_position_internal(scroll_position, true, false, cx);
|
||||
// }
|
||||
|
||||
pub(crate) fn set_scroll_position_internal(
|
||||
&mut self,
|
||||
scroll_position: Point<Pixels>,
|
||||
local: bool,
|
||||
autoscroll: bool,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
// pub(crate) fn set_scroll_position_internal(
|
||||
// &mut self,
|
||||
// scroll_position: gpui::Point<Pixels>,
|
||||
// local: bool,
|
||||
// autoscroll: bool,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) {
|
||||
// let map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
|
||||
hide_hover(self, cx);
|
||||
let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
self.scroll_manager.set_scroll_position(
|
||||
scroll_position,
|
||||
&map,
|
||||
local,
|
||||
autoscroll,
|
||||
workspace_id,
|
||||
cx,
|
||||
);
|
||||
// hide_hover(self, cx);
|
||||
// let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
// self.scroll_manager.set_scroll_position(
|
||||
// scroll_position,
|
||||
// &map,
|
||||
// local,
|
||||
// autoscroll,
|
||||
// workspace_id,
|
||||
// cx,
|
||||
// );
|
||||
|
||||
self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||
}
|
||||
// self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||
// }
|
||||
|
||||
pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> Point<Pixels> {
|
||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
self.scroll_manager.anchor.scroll_position(&display_map)
|
||||
}
|
||||
// pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> gpui::Point<Pixels> {
|
||||
// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
// self.scroll_manager.anchor.scroll_position(&display_map)
|
||||
// }
|
||||
|
||||
pub fn set_scroll_anchor(&mut self, scroll_anchor: ScrollAnchor, cx: &mut ViewContext<Self>) {
|
||||
hide_hover(self, cx);
|
||||
let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
let top_row = scroll_anchor
|
||||
.anchor
|
||||
.to_point(&self.buffer().read(cx).snapshot(cx))
|
||||
.row;
|
||||
self.scroll_manager
|
||||
.set_anchor(scroll_anchor, top_row, true, false, workspace_id, cx);
|
||||
}
|
||||
// pub fn set_scroll_anchor(&mut self, scroll_anchor: ScrollAnchor, cx: &mut ViewContext<Self>) {
|
||||
// hide_hover(self, cx);
|
||||
// let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
// let top_row = scroll_anchor
|
||||
// .anchor
|
||||
// .to_point(&self.buffer().read(cx).snapshot(cx))
|
||||
// .row;
|
||||
// self.scroll_manager
|
||||
// .set_anchor(scroll_anchor, top_row, true, false, workspace_id, cx);
|
||||
// }
|
||||
|
||||
pub(crate) fn set_scroll_anchor_remote(
|
||||
&mut self,
|
||||
scroll_anchor: ScrollAnchor,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
hide_hover(self, cx);
|
||||
let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
let top_row = scroll_anchor
|
||||
.anchor
|
||||
.to_point(&self.buffer().read(cx).snapshot(cx))
|
||||
.row;
|
||||
self.scroll_manager
|
||||
.set_anchor(scroll_anchor, top_row, false, false, workspace_id, cx);
|
||||
}
|
||||
// pub(crate) fn set_scroll_anchor_remote(
|
||||
// &mut self,
|
||||
// scroll_anchor: ScrollAnchor,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) {
|
||||
// hide_hover(self, cx);
|
||||
// let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
|
||||
// let top_row = scroll_anchor
|
||||
// .anchor
|
||||
// .to_point(&self.buffer().read(cx).snapshot(cx))
|
||||
// .row;
|
||||
// self.scroll_manager
|
||||
// .set_anchor(scroll_anchor, top_row, false, false, workspace_id, cx);
|
||||
// }
|
||||
|
||||
pub fn scroll_screen(&mut self, amount: &ScrollAmount, cx: &mut ViewContext<Self>) {
|
||||
if matches!(self.mode, EditorMode::SingleLine) {
|
||||
cx.propagate_action();
|
||||
return;
|
||||
}
|
||||
// pub fn scroll_screen(&mut self, amount: &ScrollAmount, cx: &mut ViewContext<Self>) {
|
||||
// if matches!(self.mode, EditorMode::SingleLine) {
|
||||
// cx.propagate_action();
|
||||
// return;
|
||||
// }
|
||||
|
||||
if self.take_rename(true, cx).is_some() {
|
||||
return;
|
||||
}
|
||||
// if self.take_rename(true, cx).is_some() {
|
||||
// return;
|
||||
// }
|
||||
|
||||
let cur_position = self.scroll_position(cx);
|
||||
let new_pos = cur_position + point(0., amount.lines(self));
|
||||
self.set_scroll_position(new_pos, cx);
|
||||
}
|
||||
// let cur_position = self.scroll_position(cx);
|
||||
// let new_pos = cur_position + point(0., amount.lines(self));
|
||||
// self.set_scroll_position(new_pos, cx);
|
||||
// }
|
||||
|
||||
/// Returns an ordering. The newest selection is:
|
||||
/// Ordering::Equal => on screen
|
||||
/// Ordering::Less => above the screen
|
||||
/// Ordering::Greater => below the screen
|
||||
pub fn newest_selection_on_screen(&self, cx: &mut AppContext) -> Ordering {
|
||||
let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
let newest_head = self
|
||||
.selections
|
||||
.newest_anchor()
|
||||
.head()
|
||||
.to_display_point(&snapshot);
|
||||
let screen_top = self
|
||||
.scroll_manager
|
||||
.anchor
|
||||
.anchor
|
||||
.to_display_point(&snapshot);
|
||||
// /// Returns an ordering. The newest selection is:
|
||||
// /// Ordering::Equal => on screen
|
||||
// /// Ordering::Less => above the screen
|
||||
// /// Ordering::Greater => below the screen
|
||||
// pub fn newest_selection_on_screen(&self, cx: &mut AppContext) -> Ordering {
|
||||
// let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
// let newest_head = self
|
||||
// .selections
|
||||
// .newest_anchor()
|
||||
// .head()
|
||||
// .to_display_point(&snapshot);
|
||||
// let screen_top = self
|
||||
// .scroll_manager
|
||||
// .anchor
|
||||
// .anchor
|
||||
// .to_display_point(&snapshot);
|
||||
|
||||
if screen_top > newest_head {
|
||||
return Ordering::Less;
|
||||
}
|
||||
// if screen_top > newest_head {
|
||||
// return Ordering::Less;
|
||||
// }
|
||||
|
||||
if let Some(visible_lines) = self.visible_line_count() {
|
||||
if newest_head.row() < screen_top.row() + visible_lines as u32 {
|
||||
return Ordering::Equal;
|
||||
}
|
||||
}
|
||||
// if let Some(visible_lines) = self.visible_line_count() {
|
||||
// if newest_head.row() < screen_top.row() + visible_lines as u32 {
|
||||
// return Ordering::Equal;
|
||||
// }
|
||||
// }
|
||||
|
||||
Ordering::Greater
|
||||
}
|
||||
// Ordering::Greater
|
||||
// }
|
||||
|
||||
pub fn read_scroll_position_from_db(
|
||||
&mut self,
|
||||
item_id: usize,
|
||||
workspace_id: WorkspaceId,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
let scroll_position = DB.get_scroll_position(item_id, workspace_id);
|
||||
if let Ok(Some((top_row, x, y))) = scroll_position {
|
||||
let top_anchor = self
|
||||
.buffer()
|
||||
.read(cx)
|
||||
.snapshot(cx)
|
||||
.anchor_at(Point::new(top_row as u32, 0), Bias::Left);
|
||||
let scroll_anchor = ScrollAnchor {
|
||||
offset: Point::new(x, y),
|
||||
anchor: top_anchor,
|
||||
};
|
||||
self.set_scroll_anchor(scroll_anchor, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
// pub fn read_scroll_position_from_db(
|
||||
// &mut self,
|
||||
// item_id: usize,
|
||||
// workspace_id: WorkspaceId,
|
||||
// cx: &mut ViewContext<Editor>,
|
||||
// ) {
|
||||
// let scroll_position = DB.get_scroll_position(item_id, workspace_id);
|
||||
// if let Ok(Some((top_row, x, y))) = scroll_position {
|
||||
// let top_anchor = self
|
||||
// .buffer()
|
||||
// .read(cx)
|
||||
// .snapshot(cx)
|
||||
// .anchor_at(Point::new(top_row as u32, 0), Bias::Left);
|
||||
// let scroll_anchor = ScrollAnchor {
|
||||
// offset: Point::new(x, y),
|
||||
// anchor: top_anchor,
|
||||
// };
|
||||
// self.set_scroll_anchor(scroll_anchor, cx);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -593,29 +593,30 @@ impl<'a> MutableSelectionsCollection<'a> {
|
|||
}
|
||||
|
||||
pub fn select_anchor_ranges<I: IntoIterator<Item = Range<Anchor>>>(&mut self, ranges: I) {
|
||||
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
||||
let selections = ranges
|
||||
.into_iter()
|
||||
.map(|range| {
|
||||
let mut start = range.start;
|
||||
let mut end = range.end;
|
||||
let reversed = if start.cmp(&end, &buffer).is_gt() {
|
||||
mem::swap(&mut start, &mut end);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
Selection {
|
||||
id: post_inc(&mut self.collection.next_selection_id),
|
||||
start,
|
||||
end,
|
||||
reversed,
|
||||
goal: SelectionGoal::None,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
todo!()
|
||||
// let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
||||
// let selections = ranges
|
||||
// .into_iter()
|
||||
// .map(|range| {
|
||||
// let mut start = range.start;
|
||||
// let mut end = range.end;
|
||||
// let reversed = if start.cmp(&end, &buffer).is_gt() {
|
||||
// mem::swap(&mut start, &mut end);
|
||||
// true
|
||||
// } else {
|
||||
// false
|
||||
// };
|
||||
// Selection {
|
||||
// id: post_inc(&mut self.collection.next_selection_id),
|
||||
// start,
|
||||
// end,
|
||||
// reversed,
|
||||
// goal: SelectionGoal::None,
|
||||
// }
|
||||
// })
|
||||
// .collect::<Vec<_>>();
|
||||
|
||||
self.select_anchors(selections)
|
||||
// self.select_anchors(selections)
|
||||
}
|
||||
|
||||
pub fn new_selection_id(&mut self) -> usize {
|
||||
|
|
|
@ -1,80 +1,81 @@
|
|||
pub mod editor_lsp_test_context;
|
||||
pub mod editor_test_context;
|
||||
|
||||
use crate::{
|
||||
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
|
||||
DisplayPoint, Editor, EditorMode, MultiBuffer,
|
||||
};
|
||||
// todo!()
|
||||
// use crate::{
|
||||
// display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
|
||||
// DisplayPoint, Editor, EditorMode, MultiBuffer,
|
||||
// };
|
||||
|
||||
use gpui::{Model, ViewContext};
|
||||
// use gpui::{Model, ViewContext};
|
||||
|
||||
use project::Project;
|
||||
use util::test::{marked_text_offsets, marked_text_ranges};
|
||||
// use project::Project;
|
||||
// use util::test::{marked_text_offsets, marked_text_ranges};
|
||||
|
||||
#[cfg(test)]
|
||||
#[ctor::ctor]
|
||||
fn init_logger() {
|
||||
if std::env::var("RUST_LOG").is_ok() {
|
||||
env_logger::init();
|
||||
}
|
||||
}
|
||||
// #[cfg(test)]
|
||||
// #[ctor::ctor]
|
||||
// fn init_logger() {
|
||||
// if std::env::var("RUST_LOG").is_ok() {
|
||||
// env_logger::init();
|
||||
// }
|
||||
// }
|
||||
|
||||
// Returns a snapshot from text containing '|' character markers with the markers removed, and DisplayPoints for each one.
|
||||
pub fn marked_display_snapshot(
|
||||
text: &str,
|
||||
cx: &mut gpui::AppContext,
|
||||
) -> (DisplaySnapshot, Vec<DisplayPoint>) {
|
||||
let (unmarked_text, markers) = marked_text_offsets(text);
|
||||
// // Returns a snapshot from text containing '|' character markers with the markers removed, and DisplayPoints for each one.
|
||||
// pub fn marked_display_snapshot(
|
||||
// text: &str,
|
||||
// cx: &mut gpui::AppContext,
|
||||
// ) -> (DisplaySnapshot, Vec<DisplayPoint>) {
|
||||
// let (unmarked_text, markers) = marked_text_offsets(text);
|
||||
|
||||
let family_id = cx
|
||||
.font_cache()
|
||||
.load_family(&["Helvetica"], &Default::default())
|
||||
.unwrap();
|
||||
let font_id = cx
|
||||
.font_cache()
|
||||
.select_font(family_id, &Default::default())
|
||||
.unwrap();
|
||||
let font_size = 14.0;
|
||||
// let family_id = cx
|
||||
// .font_cache()
|
||||
// .load_family(&["Helvetica"], &Default::default())
|
||||
// .unwrap();
|
||||
// let font_id = cx
|
||||
// .font_cache()
|
||||
// .select_font(family_id, &Default::default())
|
||||
// .unwrap();
|
||||
// let font_size = 14.0;
|
||||
|
||||
let buffer = MultiBuffer::build_simple(&unmarked_text, cx);
|
||||
let display_map =
|
||||
cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, None, 1, 1, cx));
|
||||
let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
let markers = markers
|
||||
.into_iter()
|
||||
.map(|offset| offset.to_display_point(&snapshot))
|
||||
.collect();
|
||||
// let buffer = MultiBuffer::build_simple(&unmarked_text, cx);
|
||||
// let display_map =
|
||||
// cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, None, 1, 1, cx));
|
||||
// let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
// let markers = markers
|
||||
// .into_iter()
|
||||
// .map(|offset| offset.to_display_point(&snapshot))
|
||||
// .collect();
|
||||
|
||||
(snapshot, markers)
|
||||
}
|
||||
// (snapshot, markers)
|
||||
// }
|
||||
|
||||
pub fn select_ranges(editor: &mut Editor, marked_text: &str, cx: &mut ViewContext<Editor>) {
|
||||
let (unmarked_text, text_ranges) = marked_text_ranges(marked_text, true);
|
||||
assert_eq!(editor.text(cx), unmarked_text);
|
||||
editor.change_selections(None, cx, |s| s.select_ranges(text_ranges));
|
||||
}
|
||||
// pub fn select_ranges(editor: &mut Editor, marked_text: &str, cx: &mut ViewContext<Editor>) {
|
||||
// let (unmarked_text, text_ranges) = marked_text_ranges(marked_text, true);
|
||||
// assert_eq!(editor.text(cx), unmarked_text);
|
||||
// editor.change_selections(None, cx, |s| s.select_ranges(text_ranges));
|
||||
// }
|
||||
|
||||
pub fn assert_text_with_selections(
|
||||
editor: &mut Editor,
|
||||
marked_text: &str,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
let (unmarked_text, text_ranges) = marked_text_ranges(marked_text, true);
|
||||
assert_eq!(editor.text(cx), unmarked_text);
|
||||
assert_eq!(editor.selections.ranges(cx), text_ranges);
|
||||
}
|
||||
// pub fn assert_text_with_selections(
|
||||
// editor: &mut Editor,
|
||||
// marked_text: &str,
|
||||
// cx: &mut ViewContext<Editor>,
|
||||
// ) {
|
||||
// let (unmarked_text, text_ranges) = marked_text_ranges(marked_text, true);
|
||||
// assert_eq!(editor.text(cx), unmarked_text);
|
||||
// assert_eq!(editor.selections.ranges(cx), text_ranges);
|
||||
// }
|
||||
|
||||
// RA thinks this is dead code even though it is used in a whole lot of tests
|
||||
#[allow(dead_code)]
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub(crate) fn build_editor(buffer: Model<MultiBuffer>, cx: &mut ViewContext<Editor>) -> Editor {
|
||||
Editor::new(EditorMode::Full, buffer, None, None, cx)
|
||||
}
|
||||
// // RA thinks this is dead code even though it is used in a whole lot of tests
|
||||
// #[allow(dead_code)]
|
||||
// #[cfg(any(test, feature = "test-support"))]
|
||||
// pub(crate) fn build_editor(buffer: Model<MultiBuffer>, cx: &mut ViewContext<Editor>) -> Editor {
|
||||
// Editor::new(EditorMode::Full, buffer, None, None, cx)
|
||||
// }
|
||||
|
||||
pub(crate) fn build_editor_with_project(
|
||||
project: Model<Project>,
|
||||
buffer: Model<MultiBuffer>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Editor {
|
||||
Editor::new(EditorMode::Full, buffer, Some(project), None, cx)
|
||||
}
|
||||
// pub(crate) fn build_editor_with_project(
|
||||
// project: Model<Project>,
|
||||
// buffer: Model<MultiBuffer>,
|
||||
// cx: &mut ViewContext<Editor>,
|
||||
// ) -> Editor {
|
||||
// Editor::new(EditorMode::Full, buffer, Some(project), None, cx)
|
||||
// }
|
||||
|
|
|
@ -17,106 +17,106 @@ use util::{
|
|||
test::{generate_marked_text, marked_text_ranges},
|
||||
};
|
||||
|
||||
use super::build_editor_with_project;
|
||||
// use super::build_editor_with_project;
|
||||
|
||||
pub struct EditorTestContext<'a> {
|
||||
pub cx: &'a mut gpui::TestAppContext,
|
||||
pub window: AnyWindowHandle,
|
||||
pub editor: View<Editor>,
|
||||
}
|
||||
// pub struct EditorTestContext<'a> {
|
||||
// pub cx: &'a mut gpui::TestAppContext,
|
||||
// pub window: AnyWindowHandle,
|
||||
// pub editor: View<Editor>,
|
||||
// }
|
||||
|
||||
impl<'a> EditorTestContext<'a> {
|
||||
pub async fn new(cx: &'a mut gpui::TestAppContext) -> EditorTestContext<'a> {
|
||||
let fs = FakeFs::new(cx.background());
|
||||
// fs.insert_file("/file", "".to_owned()).await;
|
||||
fs.insert_tree(
|
||||
"/root",
|
||||
gpui::serde_json::json!({
|
||||
"file": "",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
let project = Project::test(fs, ["/root".as_ref()], cx).await;
|
||||
let buffer = project
|
||||
.update(cx, |project, cx| {
|
||||
project.open_local_buffer("/root/file", cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let window = cx.add_window(|cx| {
|
||||
cx.focus_self();
|
||||
build_editor_with_project(project, MultiBuffer::build_from_buffer(buffer, cx), cx)
|
||||
});
|
||||
let editor = window.root(cx);
|
||||
Self {
|
||||
cx,
|
||||
window: window.into(),
|
||||
editor,
|
||||
}
|
||||
}
|
||||
// impl<'a> EditorTestContext<'a> {
|
||||
// pub async fn new(cx: &'a mut gpui::TestAppContext) -> EditorTestContext<'a> {
|
||||
// let fs = FakeFs::new(cx.background());
|
||||
// // fs.insert_file("/file", "".to_owned()).await;
|
||||
// fs.insert_tree(
|
||||
// "/root",
|
||||
// gpui::serde_json::json!({
|
||||
// "file": "",
|
||||
// }),
|
||||
// )
|
||||
// .await;
|
||||
// let project = Project::test(fs, ["/root".as_ref()], cx).await;
|
||||
// let buffer = project
|
||||
// .update(cx, |project, cx| {
|
||||
// project.open_local_buffer("/root/file", cx)
|
||||
// })
|
||||
// .await
|
||||
// .unwrap();
|
||||
// let window = cx.add_window(|cx| {
|
||||
// cx.focus_self();
|
||||
// build_editor_with_project(project, MultiBuffer::build_from_buffer(buffer, cx), cx)
|
||||
// });
|
||||
// let editor = window.root(cx);
|
||||
// Self {
|
||||
// cx,
|
||||
// window: window.into(),
|
||||
// editor,
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn condition(
|
||||
&self,
|
||||
predicate: impl FnMut(&Editor, &AppContext) -> bool,
|
||||
) -> impl Future<Output = ()> {
|
||||
self.editor.condition(self.cx, predicate)
|
||||
}
|
||||
// pub fn condition(
|
||||
// &self,
|
||||
// predicate: impl FnMut(&Editor, &AppContext) -> bool,
|
||||
// ) -> impl Future<Output = ()> {
|
||||
// self.editor.condition(self.cx, predicate)
|
||||
// }
|
||||
|
||||
pub fn editor<F, T>(&self, read: F) -> T
|
||||
where
|
||||
F: FnOnce(&Editor, &ViewContext<Editor>) -> T,
|
||||
{
|
||||
self.editor.read_with(self.cx, read)
|
||||
}
|
||||
// pub fn editor<F, T>(&self, read: F) -> T
|
||||
// where
|
||||
// F: FnOnce(&Editor, &ViewContext<Editor>) -> T,
|
||||
// {
|
||||
// self.editor.update(self.cx, read)
|
||||
// }
|
||||
|
||||
pub fn update_editor<F, T>(&mut self, update: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Editor, &mut ViewContext<Editor>) -> T,
|
||||
{
|
||||
self.editor.update(self.cx, update)
|
||||
}
|
||||
// pub fn update_editor<F, T>(&mut self, update: F) -> T
|
||||
// where
|
||||
// F: FnOnce(&mut Editor, &mut ViewContext<Editor>) -> T,
|
||||
// {
|
||||
// self.editor.update(self.cx, update)
|
||||
// }
|
||||
|
||||
pub fn multibuffer<F, T>(&self, read: F) -> T
|
||||
where
|
||||
F: FnOnce(&MultiBuffer, &AppContext) -> T,
|
||||
{
|
||||
self.editor(|editor, cx| read(editor.buffer().read(cx), cx))
|
||||
}
|
||||
// pub fn multibuffer<F, T>(&self, read: F) -> T
|
||||
// where
|
||||
// F: FnOnce(&MultiBuffer, &AppContext) -> T,
|
||||
// {
|
||||
// self.editor(|editor, cx| read(editor.buffer().read(cx), cx))
|
||||
// }
|
||||
|
||||
pub fn update_multibuffer<F, T>(&mut self, update: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut MultiBuffer, &mut ModelContext<MultiBuffer>) -> T,
|
||||
{
|
||||
self.update_editor(|editor, cx| editor.buffer().update(cx, update))
|
||||
}
|
||||
// pub fn update_multibuffer<F, T>(&mut self, update: F) -> T
|
||||
// where
|
||||
// F: FnOnce(&mut MultiBuffer, &mut ModelContext<MultiBuffer>) -> T,
|
||||
// {
|
||||
// self.update_editor(|editor, cx| editor.buffer().update(cx, update))
|
||||
// }
|
||||
|
||||
pub fn buffer_text(&self) -> String {
|
||||
self.multibuffer(|buffer, cx| buffer.snapshot(cx).text())
|
||||
}
|
||||
// pub fn buffer_text(&self) -> String {
|
||||
// self.multibuffer(|buffer, cx| buffer.snapshot(cx).text())
|
||||
// }
|
||||
|
||||
pub fn buffer<F, T>(&self, read: F) -> T
|
||||
where
|
||||
F: FnOnce(&Buffer, &AppContext) -> T,
|
||||
{
|
||||
self.multibuffer(|multibuffer, cx| {
|
||||
let buffer = multibuffer.as_singleton().unwrap().read(cx);
|
||||
read(buffer, cx)
|
||||
})
|
||||
}
|
||||
// pub fn buffer<F, T>(&self, read: F) -> T
|
||||
// where
|
||||
// F: FnOnce(&Buffer, &AppContext) -> T,
|
||||
// {
|
||||
// self.multibuffer(|multibuffer, cx| {
|
||||
// let buffer = multibuffer.as_singleton().unwrap().read(cx);
|
||||
// read(buffer, cx)
|
||||
// })
|
||||
// }
|
||||
|
||||
pub fn update_buffer<F, T>(&mut self, update: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Buffer, &mut ModelContext<Buffer>) -> T,
|
||||
{
|
||||
self.update_multibuffer(|multibuffer, cx| {
|
||||
let buffer = multibuffer.as_singleton().unwrap();
|
||||
buffer.update(cx, update)
|
||||
})
|
||||
}
|
||||
// pub fn update_buffer<F, T>(&mut self, update: F) -> T
|
||||
// where
|
||||
// F: FnOnce(&mut Buffer, &mut ModelContext<Buffer>) -> T,
|
||||
// {
|
||||
// self.update_multibuffer(|multibuffer, cx| {
|
||||
// let buffer = multibuffer.as_singleton().unwrap();
|
||||
// buffer.update(cx, update)
|
||||
// })
|
||||
// }
|
||||
|
||||
pub fn buffer_snapshot(&self) -> BufferSnapshot {
|
||||
self.buffer(|buffer, _| buffer.snapshot())
|
||||
}
|
||||
// pub fn buffer_snapshot(&self) -> BufferSnapshot {
|
||||
// self.buffer(|buffer, _| buffer.snapshot())
|
||||
// }
|
||||
|
||||
// pub fn simulate_keystroke(&mut self, keystroke_text: &str) -> ContextHandle {
|
||||
// let keystroke_under_test_handle =
|
||||
|
@ -150,31 +150,31 @@ impl<'a> EditorTestContext<'a> {
|
|||
// keystrokes_under_test_handle
|
||||
// }
|
||||
|
||||
pub fn ranges(&self, marked_text: &str) -> Vec<Range<usize>> {
|
||||
let (unmarked_text, ranges) = marked_text_ranges(marked_text, false);
|
||||
assert_eq!(self.buffer_text(), unmarked_text);
|
||||
ranges
|
||||
}
|
||||
// pub fn ranges(&self, marked_text: &str) -> Vec<Range<usize>> {
|
||||
// let (unmarked_text, ranges) = marked_text_ranges(marked_text, false);
|
||||
// assert_eq!(self.buffer_text(), unmarked_text);
|
||||
// ranges
|
||||
// }
|
||||
|
||||
pub fn display_point(&mut self, marked_text: &str) -> DisplayPoint {
|
||||
let ranges = self.ranges(marked_text);
|
||||
let snapshot = self
|
||||
.editor
|
||||
.update(self.cx, |editor, cx| editor.snapshot(cx));
|
||||
ranges[0].start.to_display_point(&snapshot)
|
||||
}
|
||||
// pub fn display_point(&mut self, marked_text: &str) -> DisplayPoint {
|
||||
// let ranges = self.ranges(marked_text);
|
||||
// let snapshot = self
|
||||
// .editor
|
||||
// .update(self.cx, |editor, cx| editor.snapshot(cx));
|
||||
// ranges[0].start.to_display_point(&snapshot)
|
||||
// }
|
||||
|
||||
// Returns anchors for the current buffer using `«` and `»`
|
||||
pub fn text_anchor_range(&self, marked_text: &str) -> Range<language::Anchor> {
|
||||
let ranges = self.ranges(marked_text);
|
||||
let snapshot = self.buffer_snapshot();
|
||||
snapshot.anchor_before(ranges[0].start)..snapshot.anchor_after(ranges[0].end)
|
||||
}
|
||||
// // Returns anchors for the current buffer using `«` and `»`
|
||||
// pub fn text_anchor_range(&self, marked_text: &str) -> Range<language::Anchor> {
|
||||
// let ranges = self.ranges(marked_text);
|
||||
// let snapshot = self.buffer_snapshot();
|
||||
// snapshot.anchor_before(ranges[0].start)..snapshot.anchor_after(ranges[0].end)
|
||||
// }
|
||||
|
||||
pub fn set_diff_base(&mut self, diff_base: Option<&str>) {
|
||||
let diff_base = diff_base.map(String::from);
|
||||
self.update_buffer(|buffer, cx| buffer.set_diff_base(diff_base, cx));
|
||||
}
|
||||
// pub fn set_diff_base(&mut self, diff_base: Option<&str>) {
|
||||
// let diff_base = diff_base.map(String::from);
|
||||
// self.update_buffer(|buffer, cx| buffer.set_diff_base(diff_base, cx));
|
||||
// }
|
||||
|
||||
// /// Change the editor's text and selections using a string containing
|
||||
// /// embedded range markers that represent the ranges and directions of
|
||||
|
@ -314,7 +314,7 @@ impl<'a> EditorTestContext<'a> {
|
|||
// );
|
||||
// }
|
||||
// }
|
||||
}
|
||||
// }
|
||||
|
||||
impl<'a> Deref for EditorTestContext<'a> {
|
||||
type Target = gpui::TestAppContext;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue