Detailed changes
@@ -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 {
- Timer::after(interval).await;
- if let Some(this) = this.upgrade(&cx) {
- this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
- }
- }
+ cx.spawn(|this, mut cx| async move {
+ Timer::after(interval).await;
+ this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
})
.detach();
}
@@ -68,13 +64,10 @@ impl BlinkManager {
let epoch = self.next_blink_epoch();
let interval = self.blink_interval;
- cx.spawn(|this, mut cx| {
- let this = this.downgrade();
- async move {
- Timer::after(interval).await;
- if let Some(this) = this.upgrade(&cx) {
- this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
- }
+ cx.spawn(|this, mut cx| async move {
+ Timer::after(interval).await;
+ 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));
-
- 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();
-
- 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(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,
- }
- })
- }
+ // 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);
+ // }
+ // }
+
+ // let mut diagnostic_highlight = HighlightStyle::default();
+
+ // 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 {
+ // 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);
+ // }
+
+ // 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)]
@@ -19,7 +19,6 @@ pub mod selections_collection;
mod editor_tests;
#[cfg(any(test, feature = "test-support"))]
pub mod test;
-
use ::git::diff::DiffHunk;
use aho_corasick::AhoCorasick;
use anyhow::{anyhow, Context, Result};
@@ -38,8 +37,9 @@ pub use element::{
use futures::FutureExt;
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
- serde_json, AnyElement, AppContext, AsyncAppContext, ClipboardItem, Element, Entity, Hsla,
- Model, Quad, Subscription, Task, Text, View, ViewContext, WeakView, WindowContext,
+ serde_json, AnyElement, AppContext, AsyncAppContext, ClipboardItem, Element, Entity,
+ EventEmitter, FontWeight, HighlightStyle, Hsla, Model, Pixels, Quad, Render, Subscription,
+ Task, Text, View, ViewContext, WeakView, WindowContext,
};
use highlight_matching_bracket::refresh_matching_bracket_highlights;
use hover_popover::{hide_hover, HoverState};
@@ -74,30 +74,17 @@ use rpc::proto::{self, PeerId};
use scroll::{
autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
};
-use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
+use selections_collection::SelectionsCollection;
use serde::{Deserialize, Serialize};
-use settings::SettingsStore;
-use smallvec::SmallVec;
-use snippet::Snippet;
+use settings::Settings;
use std::{
- any::TypeId,
- borrow::Cow,
- cmp::{self, Ordering, Reverse},
- mem,
- num::NonZeroU32,
- ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
- path::Path,
+ ops::{Deref, DerefMut, Range},
sync::Arc,
- time::{Duration, Instant},
+ time::Duration,
};
pub use sum_tree::Bias;
-use sum_tree::TreeMap;
-use text::Rope;
-use theme::{DiagnosticStyle, Theme, ThemeSettings};
-use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
-use workspace::{ItemNavHistory, SplitDirection, ViewId, Workspace};
-
-use crate::git::diff_hunk_to_display;
+use util::TryFutureExt;
+use workspace::{ItemNavHistory, ViewId, Workspace};
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
const MAX_LINE_LEN: usize = 1024;
@@ -109,70 +96,70 @@ pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis
pub const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
-pub fn render_parsed_markdown<Tag: 'static>(
- parsed: &language::ParsedMarkdown,
- editor_style: &EditorStyle,
- workspace: Option<WeakView<Workspace>>,
- cx: &mut ViewContext<Editor>,
-) -> Text {
- enum RenderedMarkdown {}
-
- let parsed = parsed.clone();
- let view_id = cx.view_id();
- let code_span_background_color = editor_style.document_highlight_read_background;
-
- let mut region_id = 0;
-
- todo!()
- // Text::new(parsed.text, editor_style.text.clone())
- // .with_highlights(
- // parsed
- // .highlights
- // .iter()
- // .filter_map(|(range, highlight)| {
- // let highlight = highlight.to_highlight_style(&editor_style.syntax)?;
- // Some((range.clone(), highlight))
- // })
- // .collect::<Vec<_>>(),
- // )
- // .with_custom_runs(parsed.region_ranges, move |ix, bounds, cx| {
- // region_id += 1;
- // let region = parsed.regions[ix].clone();
-
- // if let Some(link) = region.link {
- // cx.scene().push_cursor_region(CursorRegion {
- // bounds,
- // style: CursorStyle::PointingHand,
- // });
- // cx.scene().push_mouse_region(
- // MouseRegion::new::<(RenderedMarkdown, Tag)>(view_id, region_id, bounds)
- // .on_down::<Editor, _>(MouseButton::Left, move |_, _, cx| match &link {
- // markdown::Link::Web { url } => cx.platform().open_url(url),
- // markdown::Link::Path { path } => {
- // if let Some(workspace) = &workspace {
- // _ = workspace.update(cx, |workspace, cx| {
- // workspace.open_abs_path(path.clone(), false, cx).detach();
- // });
- // }
- // }
- // }),
- // );
- // }
-
- // if region.code {
- // cx.draw_quad(Quad {
- // bounds,
- // background: Some(code_span_background_color),
- // corner_radii: (2.0).into(),
- // order: todo!(),
- // content_mask: todo!(),
- // border_color: todo!(),
- // border_widths: todo!(),
- // });
- // }
- // })
- // .with_soft_wrap(true)
-}
+// pub fn render_parsed_markdown<Tag: 'static>(
+// parsed: &language::ParsedMarkdown,
+// editor_style: &EditorStyle,
+// workspace: Option<WeakView<Workspace>>,
+// cx: &mut ViewContext<Editor>,
+// ) -> Text {
+// enum RenderedMarkdown {}
+
+// let parsed = parsed.clone();
+// let view_id = cx.view_id();
+// let code_span_background_color = editor_style.document_highlight_read_background;
+
+// let mut region_id = 0;
+
+// todo!()
+// // Text::new(parsed.text, editor_style.text.clone())
+// // .with_highlights(
+// // parsed
+// // .highlights
+// // .iter()
+// // .filter_map(|(range, highlight)| {
+// // let highlight = highlight.to_highlight_style(&editor_style.syntax)?;
+// // Some((range.clone(), highlight))
+// // })
+// // .collect::<Vec<_>>(),
+// // )
+// // .with_custom_runs(parsed.region_ranges, move |ix, bounds, cx| {
+// // region_id += 1;
+// // let region = parsed.regions[ix].clone();
+
+// // if let Some(link) = region.link {
+// // cx.scene().push_cursor_region(CursorRegion {
+// // bounds,
+// // style: CursorStyle::PointingHand,
+// // });
+// // cx.scene().push_mouse_region(
+// // MouseRegion::new::<(RenderedMarkdown, Tag)>(view_id, region_id, bounds)
+// // .on_down::<Editor, _>(MouseButton::Left, move |_, _, cx| match &link {
+// // markdown::Link::Web { url } => cx.platform().open_url(url),
+// // markdown::Link::Path { path } => {
+// // if let Some(workspace) = &workspace {
+// // _ = workspace.update(cx, |workspace, cx| {
+// // workspace.open_abs_path(path.clone(), false, cx).detach();
+// // });
+// // }
+// // }
+// // }),
+// // );
+// // }
+
+// // if region.code {
+// // cx.draw_quad(Quad {
+// // bounds,
+// // background: Some(code_span_background_color),
+// // corner_radii: (2.0).into(),
+// // order: todo!(),
+// // content_mask: todo!(),
+// // border_color: todo!(),
+// // border_widths: todo!(),
+// // });
+// // }
+// // })
+// // .with_soft_wrap(true)
+// }
#[derive(Clone, Deserialize, PartialEq, Default)]
pub struct SelectNext {
@@ -270,138 +257,138 @@ impl InlayId {
}
}
-actions!(
- editor,
- [
- Cancel,
- Backspace,
- Delete,
- Newline,
- NewlineAbove,
- NewlineBelow,
- GoToDiagnostic,
- GoToPrevDiagnostic,
- GoToHunk,
- GoToPrevHunk,
- Indent,
- Outdent,
- DeleteLine,
- DeleteToPreviousWordStart,
- DeleteToPreviousSubwordStart,
- DeleteToNextWordEnd,
- DeleteToNextSubwordEnd,
- DeleteToBeginningOfLine,
- DeleteToEndOfLine,
- CutToEndOfLine,
- DuplicateLine,
- MoveLineUp,
- MoveLineDown,
- JoinLines,
- SortLinesCaseSensitive,
- SortLinesCaseInsensitive,
- ReverseLines,
- ShuffleLines,
- ConvertToUpperCase,
- ConvertToLowerCase,
- ConvertToTitleCase,
- ConvertToSnakeCase,
- ConvertToKebabCase,
- ConvertToUpperCamelCase,
- ConvertToLowerCamelCase,
- Transpose,
- Cut,
- Copy,
- Paste,
- Undo,
- Redo,
- MoveUp,
- PageUp,
- MoveDown,
- PageDown,
- MoveLeft,
- MoveRight,
- MoveToPreviousWordStart,
- MoveToPreviousSubwordStart,
- MoveToNextWordEnd,
- MoveToNextSubwordEnd,
- MoveToBeginningOfLine,
- MoveToEndOfLine,
- MoveToStartOfParagraph,
- MoveToEndOfParagraph,
- MoveToBeginning,
- MoveToEnd,
- SelectUp,
- SelectDown,
- SelectLeft,
- SelectRight,
- SelectToPreviousWordStart,
- SelectToPreviousSubwordStart,
- SelectToNextWordEnd,
- SelectToNextSubwordEnd,
- SelectToStartOfParagraph,
- SelectToEndOfParagraph,
- SelectToBeginning,
- SelectToEnd,
- SelectAll,
- SelectLine,
- SplitSelectionIntoLines,
- AddSelectionAbove,
- AddSelectionBelow,
- Tab,
- TabPrev,
- ShowCharacterPalette,
- SelectLargerSyntaxNode,
- SelectSmallerSyntaxNode,
- GoToDefinition,
- GoToDefinitionSplit,
- GoToTypeDefinition,
- GoToTypeDefinitionSplit,
- MoveToEnclosingBracket,
- UndoSelection,
- RedoSelection,
- FindAllReferences,
- Rename,
- ConfirmRename,
- Fold,
- UnfoldLines,
- FoldSelectedRanges,
- ShowCompletions,
- OpenExcerpts,
- RestartLanguageServer,
- Hover,
- Format,
- ToggleSoftWrap,
- ToggleInlayHints,
- RevealInFinder,
- CopyPath,
- CopyRelativePath,
- CopyHighlightJson,
- ContextMenuFirst,
- ContextMenuPrev,
- ContextMenuNext,
- ContextMenuLast,
- ]
-);
-
-impl_actions!(
- editor,
- [
- SelectNext,
- SelectPrevious,
- SelectAllMatches,
- SelectToBeginningOfLine,
- SelectToEndOfLine,
- ToggleCodeActions,
- MovePageUp,
- MovePageDown,
- ConfirmCompletion,
- ConfirmCodeAction,
- ToggleComments,
- FoldAt,
- UnfoldAt,
- GutterHover
- ]
-);
+// actions!(
+// editor,
+// [
+// Cancel,
+// Backspace,
+// Delete,
+// Newline,
+// NewlineAbove,
+// NewlineBelow,
+// GoToDiagnostic,
+// GoToPrevDiagnostic,
+// GoToHunk,
+// GoToPrevHunk,
+// Indent,
+// Outdent,
+// DeleteLine,
+// DeleteToPreviousWordStart,
+// DeleteToPreviousSubwordStart,
+// DeleteToNextWordEnd,
+// DeleteToNextSubwordEnd,
+// DeleteToBeginningOfLine,
+// DeleteToEndOfLine,
+// CutToEndOfLine,
+// DuplicateLine,
+// MoveLineUp,
+// MoveLineDown,
+// JoinLines,
+// SortLinesCaseSensitive,
+// SortLinesCaseInsensitive,
+// ReverseLines,
+// ShuffleLines,
+// ConvertToUpperCase,
+// ConvertToLowerCase,
+// ConvertToTitleCase,
+// ConvertToSnakeCase,
+// ConvertToKebabCase,
+// ConvertToUpperCamelCase,
+// ConvertToLowerCamelCase,
+// Transpose,
+// Cut,
+// Copy,
+// Paste,
+// Undo,
+// Redo,
+// MoveUp,
+// PageUp,
+// MoveDown,
+// PageDown,
+// MoveLeft,
+// MoveRight,
+// MoveToPreviousWordStart,
+// MoveToPreviousSubwordStart,
+// MoveToNextWordEnd,
+// MoveToNextSubwordEnd,
+// MoveToBeginningOfLine,
+// MoveToEndOfLine,
+// MoveToStartOfParagraph,
+// MoveToEndOfParagraph,
+// MoveToBeginning,
+// MoveToEnd,
+// SelectUp,
+// SelectDown,
+// SelectLeft,
+// SelectRight,
+// SelectToPreviousWordStart,
+// SelectToPreviousSubwordStart,
+// SelectToNextWordEnd,
+// SelectToNextSubwordEnd,
+// SelectToStartOfParagraph,
+// SelectToEndOfParagraph,
+// SelectToBeginning,
+// SelectToEnd,
+// SelectAll,
+// SelectLine,
+// SplitSelectionIntoLines,
+// AddSelectionAbove,
+// AddSelectionBelow,
+// Tab,
+// TabPrev,
+// ShowCharacterPalette,
+// SelectLargerSyntaxNode,
+// SelectSmallerSyntaxNode,
+// GoToDefinition,
+// GoToDefinitionSplit,
+// GoToTypeDefinition,
+// GoToTypeDefinitionSplit,
+// MoveToEnclosingBracket,
+// UndoSelection,
+// RedoSelection,
+// FindAllReferences,
+// Rename,
+// ConfirmRename,
+// Fold,
+// UnfoldLines,
+// FoldSelectedRanges,
+// ShowCompletions,
+// OpenExcerpts,
+// RestartLanguageServer,
+// Hover,
+// Format,
+// ToggleSoftWrap,
+// ToggleInlayHints,
+// RevealInFinder,
+// CopyPath,
+// CopyRelativePath,
+// CopyHighlightJson,
+// ContextMenuFirst,
+// ContextMenuPrev,
+// ContextMenuNext,
+// ContextMenuLast,
+// ]
+// );
+
+// impl_actions!(
+// editor,
+// [
+// SelectNext,
+// SelectPrevious,
+// SelectAllMatches,
+// SelectToBeginningOfLine,
+// SelectToEndOfLine,
+// ToggleCodeActions,
+// MovePageUp,
+// MovePageDown,
+// ConfirmCompletion,
+// ConfirmCodeAction,
+// ToggleComments,
+// FoldAt,
+// UnfoldAt,
+// GutterHover
+// ]
+// );
enum DocumentHighlightRead {}
enum DocumentHighlightWrite {}
@@ -414,7 +401,7 @@ pub enum Direction {
}
pub fn init_settings(cx: &mut AppContext) {
- settings::register::<EditorSettings>(cx);
+ EditorSettings::register(cx);
}
pub fn init(cx: &mut AppContext) {
@@ -574,7 +561,7 @@ pub enum SelectPhase {
Update {
position: DisplayPoint,
goal_column: u32,
- scroll_position: Point<Pixels>,
+ scroll_position: gpui::Point<Pixels>,
},
End,
}
@@ -603,20 +590,20 @@ pub enum SoftWrap {
#[derive(Clone)]
pub struct EditorStyle {
- pub text: TextStyle,
+ // pub text: TextStyle,
pub line_height_scalar: f32,
- pub placeholder_text: Option<TextStyle>,
- pub theme: theme::Editor,
+ // pub placeholder_text: Option<TextStyle>,
+ // pub theme: theme::Editor,
pub theme_id: usize,
}
type CompletionId = usize;
-type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
-type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
+// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
+// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
-type BackgroundHighlight = (fn(&Theme) -> Hsla, Vec<Range<Anchor>>);
-type InlayBackgroundHighlight = (fn(&Theme) -> Hsla, Vec<InlayHighlight>);
+// type BackgroundHighlight = (fn(&Theme) -> Hsla, Vec<Range<Anchor>>);
+// type InlayBackgroundHighlight = (fn(&Theme) -> Hsla, Vec<InlayHighlight>);
pub struct Editor {
handle: WeakView<Self>,
@@ -635,8 +622,8 @@ pub struct Editor {
ime_transaction: Option<TransactionId>,
active_diagnostics: Option<ActiveDiagnosticGroup>,
soft_wrap_mode_override: Option<language_settings::SoftWrap>,
- get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
- override_text_style: Option<Box<OverrideTextStyle>>,
+ // get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
+ // override_text_style: Option<Box<OverrideTextStyle>>,
project: Option<Model<Project>>,
collaboration_hub: Option<Box<dyn CollaborationHub>>,
focused: bool,
@@ -647,8 +634,8 @@ pub struct Editor {
show_wrap_guides: Option<bool>,
placeholder_text: Option<Arc<str>>,
highlighted_rows: Option<Range<u32>>,
- background_highlights: BTreeMap<TypeId, BackgroundHighlight>,
- inlay_background_highlights: TreeMap<Option<TypeId>, InlayBackgroundHighlight>,
+ // background_highlights: BTreeMap<TypeId, BackgroundHighlight>,
+ // inlay_background_highlights: TreeMap<Option<TypeId>, InlayBackgroundHighlight>,
nav_history: Option<ItemNavHistory>,
context_menu: RwLock<Option<ContextMenu>>,
mouse_context_menu: View<context_menu::ContextMenu>,
@@ -663,7 +650,7 @@ pub struct Editor {
collapse_matches: bool,
autoindent_mode: Option<AutoindentMode>,
workspace: Option<(WeakView<Workspace>, i64)>,
- keymap_context_layers: BTreeMap<TypeId, KeymapContext>,
+ // keymap_context_layers: BTreeMap<TypeId, KeymapContext>,
input_enabled: bool,
read_only: bool,
leader_peer_id: Option<PeerId>,
@@ -675,7 +662,7 @@ pub struct Editor {
// inlay_hint_cache: InlayHintCache,
next_inlay_id: usize,
_subscriptions: Vec<Subscription>,
- pixel_position_of_newest_cursor: Option<Point<Pixels>>,
+ pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
}
pub struct EditorSnapshot {
@@ -937,763 +924,763 @@ struct CompletionsMenu {
match_candidates: Arc<[StringMatchCandidate]>,
matches: Arc<[StringMatch]>,
selected_item: usize,
- list: UniformListState,
+ // list: UniformListState,
}
-impl CompletionsMenu {
- fn select_first(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
- self.selected_item = 0;
- self.list.scroll_to(ScrollTarget::Show(self.selected_item));
- self.attempt_resolve_selected_completion_documentation(project, cx);
- cx.notify();
- }
+// impl CompletionsMenu {
+// fn select_first(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
+// self.selected_item = 0;
+// self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+// self.attempt_resolve_selected_completion_documentation(project, cx);
+// cx.notify();
+// }
- fn select_prev(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
- if self.selected_item > 0 {
- self.selected_item -= 1;
- } else {
- self.selected_item = self.matches.len() - 1;
- }
- self.list.scroll_to(ScrollTarget::Show(self.selected_item));
- self.attempt_resolve_selected_completion_documentation(project, cx);
- cx.notify();
- }
+// fn select_prev(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
+// if self.selected_item > 0 {
+// self.selected_item -= 1;
+// } else {
+// self.selected_item = self.matches.len() - 1;
+// }
+// self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+// self.attempt_resolve_selected_completion_documentation(project, cx);
+// cx.notify();
+// }
- fn select_next(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
- if self.selected_item + 1 < self.matches.len() {
- self.selected_item += 1;
- } else {
- self.selected_item = 0;
- }
- self.list.scroll_to(ScrollTarget::Show(self.selected_item));
- self.attempt_resolve_selected_completion_documentation(project, cx);
- cx.notify();
- }
+// fn select_next(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
+// if self.selected_item + 1 < self.matches.len() {
+// self.selected_item += 1;
+// } else {
+// self.selected_item = 0;
+// }
+// self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+// self.attempt_resolve_selected_completion_documentation(project, cx);
+// cx.notify();
+// }
- fn select_last(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
- self.selected_item = self.matches.len() - 1;
- self.list.scroll_to(ScrollTarget::Show(self.selected_item));
- self.attempt_resolve_selected_completion_documentation(project, cx);
- cx.notify();
- }
+// fn select_last(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
+// self.selected_item = self.matches.len() - 1;
+// self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+// self.attempt_resolve_selected_completion_documentation(project, cx);
+// cx.notify();
+// }
- fn pre_resolve_completion_documentation(
- &self,
- project: Option<Model<Project>>,
- cx: &mut ViewContext<Editor>,
- ) {
- let settings = settings::get::<EditorSettings>(cx);
- if !settings.show_completion_documentation {
- return;
- }
+// fn pre_resolve_completion_documentation(
+// &self,
+// project: Option<Model<Project>>,
+// cx: &mut ViewContext<Editor>,
+// ) {
+// let settings = settings::get::<EditorSettings>(cx);
+// if !settings.show_completion_documentation {
+// return;
+// }
- let Some(project) = project else {
- return;
- };
- let client = project.read(cx).client();
- let language_registry = project.read(cx).languages().clone();
+// let Some(project) = project else {
+// return;
+// };
+// let client = project.read(cx).client();
+// let language_registry = project.read(cx).languages().clone();
- let is_remote = project.read(cx).is_remote();
- let project_id = project.read(cx).remote_id();
+// let is_remote = project.read(cx).is_remote();
+// let project_id = project.read(cx).remote_id();
- let completions = self.completions.clone();
- let completion_indices: Vec<_> = self.matches.iter().map(|m| m.candidate_id).collect();
+// let completions = self.completions.clone();
+// let completion_indices: Vec<_> = self.matches.iter().map(|m| m.candidate_id).collect();
- cx.spawn(move |this, mut cx| async move {
- if is_remote {
- let Some(project_id) = project_id else {
- log::error!("Remote project without remote_id");
- return;
- };
+// cx.spawn(move |this, mut cx| async move {
+// if is_remote {
+// let Some(project_id) = project_id else {
+// log::error!("Remote project without remote_id");
+// return;
+// };
- for completion_index in completion_indices {
- let completions_guard = completions.read();
- let completion = &completions_guard[completion_index];
- if completion.documentation.is_some() {
- continue;
- }
-
- let server_id = completion.server_id;
- let completion = completion.lsp_completion.clone();
- drop(completions_guard);
-
- Self::resolve_completion_documentation_remote(
- project_id,
- server_id,
- completions.clone(),
- completion_index,
- completion,
- client.clone(),
- language_registry.clone(),
- )
- .await;
-
- _ = this.update(&mut cx, |_, cx| cx.notify());
- }
- } else {
- for completion_index in completion_indices {
- let completions_guard = completions.read();
- let completion = &completions_guard[completion_index];
- if completion.documentation.is_some() {
- continue;
- }
-
- let server_id = completion.server_id;
- let completion = completion.lsp_completion.clone();
- drop(completions_guard);
-
- let server = project.read_with(&mut cx, |project, _| {
- project.language_server_for_id(server_id)
- });
- let Some(server) = server else {
- return;
- };
-
- Self::resolve_completion_documentation_local(
- server,
- completions.clone(),
- completion_index,
- completion,
- language_registry.clone(),
- )
- .await;
-
- _ = this.update(&mut cx, |_, cx| cx.notify());
- }
- }
- })
- .detach();
- }
+// for completion_index in completion_indices {
+// let completions_guard = completions.read();
+// let completion = &completions_guard[completion_index];
+// if completion.documentation.is_some() {
+// continue;
+// }
- fn attempt_resolve_selected_completion_documentation(
- &mut self,
- project: Option<&Model<Project>>,
- cx: &mut ViewContext<Editor>,
- ) {
- let settings = settings::get::<EditorSettings>(cx);
- if !settings.show_completion_documentation {
- return;
- }
+// let server_id = completion.server_id;
+// let completion = completion.lsp_completion.clone();
+// drop(completions_guard);
+
+// Self::resolve_completion_documentation_remote(
+// project_id,
+// server_id,
+// completions.clone(),
+// completion_index,
+// completion,
+// client.clone(),
+// language_registry.clone(),
+// )
+// .await;
- let completion_index = self.matches[self.selected_item].candidate_id;
- let Some(project) = project else {
- return;
- };
- let language_registry = project.read(cx).languages().clone();
-
- let completions = self.completions.clone();
- let completions_guard = completions.read();
- let completion = &completions_guard[completion_index];
- if completion.documentation.is_some() {
- return;
- }
+// _ = this.update(&mut cx, |_, cx| cx.notify());
+// }
+// } else {
+// for completion_index in completion_indices {
+// let completions_guard = completions.read();
+// let completion = &completions_guard[completion_index];
+// if completion.documentation.is_some() {
+// continue;
+// }
- let server_id = completion.server_id;
- let completion = completion.lsp_completion.clone();
- drop(completions_guard);
+// let server_id = completion.server_id;
+// let completion = completion.lsp_completion.clone();
+// drop(completions_guard);
- if project.read(cx).is_remote() {
- let Some(project_id) = project.read(cx).remote_id() else {
- log::error!("Remote project without remote_id");
- return;
- };
-
- let client = project.read(cx).client();
-
- cx.spawn(move |this, mut cx| async move {
- Self::resolve_completion_documentation_remote(
- project_id,
- server_id,
- completions.clone(),
- completion_index,
- completion,
- client,
- language_registry.clone(),
- )
- .await;
-
- _ = this.update(&mut cx, |_, cx| cx.notify());
- })
- .detach();
- } else {
- let Some(server) = project.read(cx).language_server_for_id(server_id) else {
- return;
- };
-
- cx.spawn(move |this, mut cx| async move {
- Self::resolve_completion_documentation_local(
- server,
- completions,
- completion_index,
- completion,
- language_registry,
- )
- .await;
-
- _ = this.update(&mut cx, |_, cx| cx.notify());
- })
- .detach();
- }
- }
+// let server = project.read_with(&mut cx, |project, _| {
+// project.language_server_for_id(server_id)
+// });
+// let Some(server) = server else {
+// return;
+// };
- async fn resolve_completion_documentation_remote(
- project_id: u64,
- server_id: LanguageServerId,
- completions: Arc<RwLock<Box<[Completion]>>>,
- completion_index: usize,
- completion: lsp::CompletionItem,
- client: Arc<Client>,
- language_registry: Arc<LanguageRegistry>,
- ) {
- let request = proto::ResolveCompletionDocumentation {
- project_id,
- language_server_id: server_id.0 as u64,
- lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
- };
-
- let Some(response) = client
- .request(request)
- .await
- .context("completion documentation resolve proto request")
- .log_err()
- else {
- return;
- };
-
- if response.text.is_empty() {
- let mut completions = completions.write();
- let completion = &mut completions[completion_index];
- completion.documentation = Some(Documentation::Undocumented);
- }
+// Self::resolve_completion_documentation_local(
+// server,
+// completions.clone(),
+// completion_index,
+// completion,
+// language_registry.clone(),
+// )
+// .await;
- let documentation = if response.is_markdown {
- Documentation::MultiLineMarkdown(
- markdown::parse_markdown(&response.text, &language_registry, None).await,
- )
- } else if response.text.lines().count() <= 1 {
- Documentation::SingleLine(response.text)
- } else {
- Documentation::MultiLinePlainText(response.text)
- };
+// _ = this.update(&mut cx, |_, cx| cx.notify());
+// }
+// }
+// })
+// .detach();
+// }
- let mut completions = completions.write();
- let completion = &mut completions[completion_index];
- completion.documentation = Some(documentation);
- }
+// fn attempt_resolve_selected_completion_documentation(
+// &mut self,
+// project: Option<&Model<Project>>,
+// cx: &mut ViewContext<Editor>,
+// ) {
+// let settings = settings::get::<EditorSettings>(cx);
+// if !settings.show_completion_documentation {
+// return;
+// }
- async fn resolve_completion_documentation_local(
- server: Arc<lsp::LanguageServer>,
- completions: Arc<RwLock<Box<[Completion]>>>,
- completion_index: usize,
- completion: lsp::CompletionItem,
- language_registry: Arc<LanguageRegistry>,
- ) {
- let can_resolve = server
- .capabilities()
- .completion_provider
- .as_ref()
- .and_then(|options| options.resolve_provider)
- .unwrap_or(false);
- if !can_resolve {
- return;
- }
+// let completion_index = self.matches[self.selected_item].candidate_id;
+// let Some(project) = project else {
+// return;
+// };
+// let language_registry = project.read(cx).languages().clone();
- let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
- let Some(completion_item) = request.await.log_err() else {
- return;
- };
-
- if let Some(lsp_documentation) = completion_item.documentation {
- let documentation = language::prepare_completion_documentation(
- &lsp_documentation,
- &language_registry,
- None, // TODO: Try to reasonably work out which language the completion is for
- )
- .await;
-
- let mut completions = completions.write();
- let completion = &mut completions[completion_index];
- completion.documentation = Some(documentation);
- } else {
- let mut completions = completions.write();
- let completion = &mut completions[completion_index];
- completion.documentation = Some(Documentation::Undocumented);
- }
- }
+// let completions = self.completions.clone();
+// let completions_guard = completions.read();
+// let completion = &completions_guard[completion_index];
+// if completion.documentation.is_some() {
+// return;
+// }
- fn visible(&self) -> bool {
- !self.matches.is_empty()
- }
+// let server_id = completion.server_id;
+// let completion = completion.lsp_completion.clone();
+// drop(completions_guard);
- fn render(
- &self,
- style: EditorStyle,
- workspace: Option<WeakView<Workspace>>,
- cx: &mut ViewContext<Editor>,
- ) -> AnyElement<Editor> {
- enum CompletionTag {}
+// if project.read(cx).is_remote() {
+// let Some(project_id) = project.read(cx).remote_id() else {
+// log::error!("Remote project without remote_id");
+// return;
+// };
- let settings = settings::get::<EditorSettings>(cx);
- let show_completion_documentation = settings.show_completion_documentation;
+// let client = project.read(cx).client();
+
+// cx.spawn(move |this, mut cx| async move {
+// Self::resolve_completion_documentation_remote(
+// project_id,
+// server_id,
+// completions.clone(),
+// completion_index,
+// completion,
+// client,
+// language_registry.clone(),
+// )
+// .await;
- let widest_completion_ix = self
- .matches
- .iter()
- .enumerate()
- .max_by_key(|(_, mat)| {
- let completions = self.completions.read();
- let completion = &completions[mat.candidate_id];
- let documentation = &completion.documentation;
-
- let mut len = completion.label.text.chars().count();
- if let Some(Documentation::SingleLine(text)) = documentation {
- if show_completion_documentation {
- len += text.chars().count();
- }
- }
+// _ = this.update(&mut cx, |_, cx| cx.notify());
+// })
+// .detach();
+// } else {
+// let Some(server) = project.read(cx).language_server_for_id(server_id) else {
+// return;
+// };
- len
- })
- .map(|(ix, _)| ix);
-
- let completions = self.completions.clone();
- let matches = self.matches.clone();
- let selected_item = self.selected_item;
-
- let list = UniformList::new(self.list.clone(), matches.len(), cx, {
- let style = style.clone();
- move |_, range, items, cx| {
- let start_ix = range.start;
- let completions_guard = completions.read();
-
- for (ix, mat) in matches[range].iter().enumerate() {
- let item_ix = start_ix + ix;
- let candidate_id = mat.candidate_id;
- let completion = &completions_guard[candidate_id];
-
- let documentation = if show_completion_documentation {
- &completion.documentation
- } else {
- &None
- };
-
- items.push(
- MouseEventHandler::new::<CompletionTag, _>(
- mat.candidate_id,
- cx,
- |state, _| {
- let item_style = if item_ix == selected_item {
- style.autocomplete.selected_item
- } else if state.hovered() {
- style.autocomplete.hovered_item
- } else {
- style.autocomplete.item
- };
-
- let completion_label =
- Text::new(completion.label.text.clone(), style.text.clone())
- .with_soft_wrap(false)
- .with_highlights(
- combine_syntax_and_fuzzy_match_highlights(
- &completion.label.text,
- style.text.color.into(),
- styled_runs_for_code_label(
- &completion.label,
- &style.syntax,
- ),
- &mat.positions,
- ),
- );
-
- if let Some(Documentation::SingleLine(text)) = documentation {
- Flex::row()
- .with_child(completion_label)
- .with_children((|| {
- let text_style = TextStyle {
- color: style.autocomplete.inline_docs_color,
- font_size: style.text.font_size
- * style.autocomplete.inline_docs_size_percent,
- ..style.text.clone()
- };
-
- let label = Text::new(text.clone(), text_style)
- .aligned()
- .constrained()
- .dynamically(move |constraint, _, _| {
- gpui::SizeConstraint {
- min: constraint.min,
- max: vec2f(
- constraint.max.x(),
- constraint.min.y(),
- ),
- }
- });
-
- if Some(item_ix) == widest_completion_ix {
- Some(
- label
- .contained()
- .with_style(
- style
- .autocomplete
- .inline_docs_container,
- )
- .into_any(),
- )
- } else {
- Some(label.flex_float().into_any())
- }
- })())
- .into_any()
- } else {
- completion_label.into_any()
- }
- .contained()
- .with_style(item_style)
- .constrained()
- .dynamically(
- move |constraint, _, _| {
- if Some(item_ix) == widest_completion_ix {
- constraint
- } else {
- gpui::SizeConstraint {
- min: constraint.min,
- max: constraint.min,
- }
- }
- },
- )
- },
- )
- .with_cursor_style(CursorStyle::PointingHand)
- .on_down(MouseButton::Left, move |_, this, cx| {
- this.confirm_completion(
- &ConfirmCompletion {
- item_ix: Some(item_ix),
- },
- cx,
- )
- .map(|task| task.detach());
- })
- .constrained()
- .with_min_width(style.autocomplete.completion_min_width)
- .with_max_width(style.autocomplete.completion_max_width)
- .into_any(),
- );
- }
- }
- })
- .with_width_from_item(widest_completion_ix);
-
- enum MultiLineDocumentation {}
-
- Flex::row()
- .with_child(list.flex(1., false))
- .with_children({
- let mat = &self.matches[selected_item];
- let completions = self.completions.read();
- let completion = &completions[mat.candidate_id];
- let documentation = &completion.documentation;
-
- match documentation {
- Some(Documentation::MultiLinePlainText(text)) => Some(
- Flex::column()
- .scrollable::<MultiLineDocumentation>(0, None, cx)
- .with_child(
- Text::new(text.clone(), style.text.clone()).with_soft_wrap(true),
- )
- .contained()
- .with_style(style.autocomplete.alongside_docs_container)
- .constrained()
- .with_max_width(style.autocomplete.alongside_docs_max_width)
- .flex(1., false),
- ),
-
- Some(Documentation::MultiLineMarkdown(parsed)) => Some(
- Flex::column()
- .scrollable::<MultiLineDocumentation>(0, None, cx)
- .with_child(render_parsed_markdown::<MultiLineDocumentation>(
- parsed, &style, workspace, cx,
- ))
- .contained()
- .with_style(style.autocomplete.alongside_docs_container)
- .constrained()
- .with_max_width(style.autocomplete.alongside_docs_max_width)
- .flex(1., false),
- ),
-
- _ => None,
- }
- })
- .contained()
- .with_style(style.autocomplete.container)
- .into_any()
- }
+// cx.spawn(move |this, mut cx| async move {
+// Self::resolve_completion_documentation_local(
+// server,
+// completions,
+// completion_index,
+// completion,
+// language_registry,
+// )
+// .await;
- pub async fn filter(&mut self, query: Option<&str>, executor: Arc<executor::Background>) {
- let mut matches = if let Some(query) = query {
- fuzzy::match_strings(
- &self.match_candidates,
- query,
- query.chars().any(|c| c.is_uppercase()),
- 100,
- &Default::default(),
- executor,
- )
- .await
- } else {
- self.match_candidates
- .iter()
- .enumerate()
- .map(|(candidate_id, candidate)| StringMatch {
- candidate_id,
- score: Default::default(),
- positions: Default::default(),
- string: candidate.string.clone(),
- })
- .collect()
- };
-
- // Remove all candidates where the query's start does not match the start of any word in the candidate
- if let Some(query) = query {
- if let Some(query_start) = query.chars().next() {
- matches.retain(|string_match| {
- split_words(&string_match.string).any(|word| {
- // Check that the first codepoint of the word as lowercase matches the first
- // codepoint of the query as lowercase
- word.chars()
- .flat_map(|codepoint| codepoint.to_lowercase())
- .zip(query_start.to_lowercase())
- .all(|(word_cp, query_cp)| word_cp == query_cp)
- })
- });
- }
- }
+// _ = this.update(&mut cx, |_, cx| cx.notify());
+// })
+// .detach();
+// }
+// }
- let completions = self.completions.read();
- matches.sort_unstable_by_key(|mat| {
- let completion = &completions[mat.candidate_id];
- (
- completion.lsp_completion.sort_text.as_ref(),
- Reverse(OrderedFloat(mat.score)),
- completion.sort_key(),
- )
- });
- drop(completions);
-
- for mat in &mut matches {
- let completions = self.completions.read();
- let filter_start = completions[mat.candidate_id].label.filter_range.start;
- for position in &mut mat.positions {
- *position += filter_start;
- }
- }
+// async fn resolve_completion_documentation_remote(
+// project_id: u64,
+// server_id: LanguageServerId,
+// completions: Arc<RwLock<Box<[Completion]>>>,
+// completion_index: usize,
+// completion: lsp::CompletionItem,
+// client: Arc<Client>,
+// language_registry: Arc<LanguageRegistry>,
+// ) {
+// let request = proto::ResolveCompletionDocumentation {
+// project_id,
+// language_server_id: server_id.0 as u64,
+// lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
+// };
- self.matches = matches.into();
- self.selected_item = 0;
- }
-}
+// let Some(response) = client
+// .request(request)
+// .await
+// .context("completion documentation resolve proto request")
+// .log_err()
+// else {
+// return;
+// };
-#[derive(Clone)]
-struct CodeActionsMenu {
- actions: Arc<[CodeAction]>,
- buffer: Model<Buffer>,
- selected_item: usize,
- list: UniformListState,
- deployed_from_indicator: bool,
-}
+// if response.text.is_empty() {
+// let mut completions = completions.write();
+// let completion = &mut completions[completion_index];
+// completion.documentation = Some(Documentation::Undocumented);
+// }
-impl CodeActionsMenu {
- fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
- self.selected_item = 0;
- self.list.scroll_to(ScrollTarget::Show(self.selected_item));
- cx.notify()
- }
+// let documentation = if response.is_markdown {
+// Documentation::MultiLineMarkdown(
+// markdown::parse_markdown(&response.text, &language_registry, None).await,
+// )
+// } else if response.text.lines().count() <= 1 {
+// Documentation::SingleLine(response.text)
+// } else {
+// Documentation::MultiLinePlainText(response.text)
+// };
- fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
- if self.selected_item > 0 {
- self.selected_item -= 1;
- } else {
- self.selected_item = self.actions.len() - 1;
- }
- self.list.scroll_to(ScrollTarget::Show(self.selected_item));
- cx.notify();
- }
+// let mut completions = completions.write();
+// let completion = &mut completions[completion_index];
+// completion.documentation = Some(documentation);
+// }
- fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
- if self.selected_item + 1 < self.actions.len() {
- self.selected_item += 1;
- } else {
- self.selected_item = 0;
- }
- self.list.scroll_to(ScrollTarget::Show(self.selected_item));
- cx.notify();
- }
+// async fn resolve_completion_documentation_local(
+// server: Arc<lsp::LanguageServer>,
+// completions: Arc<RwLock<Box<[Completion]>>>,
+// completion_index: usize,
+// completion: lsp::CompletionItem,
+// language_registry: Arc<LanguageRegistry>,
+// ) {
+// let can_resolve = server
+// .capabilities()
+// .completion_provider
+// .as_ref()
+// .and_then(|options| options.resolve_provider)
+// .unwrap_or(false);
+// if !can_resolve {
+// return;
+// }
- fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
- self.selected_item = self.actions.len() - 1;
- self.list.scroll_to(ScrollTarget::Show(self.selected_item));
- cx.notify()
- }
+// let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
+// let Some(completion_item) = request.await.log_err() else {
+// return;
+// };
- fn visible(&self) -> bool {
- !self.actions.is_empty()
- }
+// if let Some(lsp_documentation) = completion_item.documentation {
+// let documentation = language::prepare_completion_documentation(
+// &lsp_documentation,
+// &language_registry,
+// None, // TODO: Try to reasonably work out which language the completion is for
+// )
+// .await;
- fn render(
- &self,
- mut cursor_position: DisplayPoint,
- style: EditorStyle,
- cx: &mut ViewContext<Editor>,
- ) -> (DisplayPoint, AnyElement<Editor>) {
- enum ActionTag {}
-
- let container_style = style.autocomplete.container;
- let actions = self.actions.clone();
- let selected_item = self.selected_item;
- let element = UniformList::new(
- self.list.clone(),
- actions.len(),
- cx,
- move |_, range, items, cx| {
- let start_ix = range.start;
- for (ix, action) in actions[range].iter().enumerate() {
- let item_ix = start_ix + ix;
- items.push(
- MouseEventHandler::new::<ActionTag, _>(item_ix, cx, |state, _| {
- let item_style = if item_ix == selected_item {
- style.autocomplete.selected_item
- } else if state.hovered() {
- style.autocomplete.hovered_item
- } else {
- style.autocomplete.item
- };
-
- Text::new(action.lsp_action.title.clone(), style.text.clone())
- .with_soft_wrap(false)
- .contained()
- .with_style(item_style)
- })
- .with_cursor_style(CursorStyle::PointingHand)
- .on_down(MouseButton::Left, move |_, this, cx| {
- let workspace = this
- .workspace
- .as_ref()
- .and_then(|(workspace, _)| workspace.upgrade(cx));
- cx.window_context().defer(move |cx| {
- if let Some(workspace) = workspace {
- workspace.update(cx, |workspace, cx| {
- if let Some(task) = Editor::confirm_code_action(
- workspace,
- &ConfirmCodeAction {
- item_ix: Some(item_ix),
- },
- cx,
- ) {
- task.detach_and_log_err(cx);
- }
- });
- }
- });
- })
- .into_any(),
- );
- }
- },
- )
- .with_width_from_item(
- self.actions
- .iter()
- .enumerate()
- .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
- .map(|(ix, _)| ix),
- )
- .contained()
- .with_style(container_style)
- .into_any();
-
- if self.deployed_from_indicator {
- *cursor_position.column_mut() = 0;
- }
+// let mut completions = completions.write();
+// let completion = &mut completions[completion_index];
+// completion.documentation = Some(documentation);
+// } else {
+// let mut completions = completions.write();
+// let completion = &mut completions[completion_index];
+// completion.documentation = Some(Documentation::Undocumented);
+// }
+// }
- (cursor_position, element)
- }
-}
+// fn visible(&self) -> bool {
+// !self.matches.is_empty()
+// }
-pub struct CopilotState {
- excerpt_id: Option<ExcerptId>,
- pending_refresh: Task<Option<()>>,
- pending_cycling_refresh: Task<Option<()>>,
- cycled: bool,
- completions: Vec<copilot::Completion>,
- active_completion_index: usize,
- suggestion: Option<Inlay>,
-}
+// fn render(
+// &self,
+// style: EditorStyle,
+// workspace: Option<WeakView<Workspace>>,
+// cx: &mut ViewContext<Editor>,
+// ) -> AnyElement<Editor> {
+// enum CompletionTag {}
-impl Default for CopilotState {
- fn default() -> Self {
- Self {
- excerpt_id: None,
- pending_cycling_refresh: Task::ready(Some(())),
- pending_refresh: Task::ready(Some(())),
- completions: Default::default(),
- active_completion_index: 0,
- cycled: false,
- suggestion: None,
- }
- }
-}
+// let settings = settings::get::<EditorSettings>(cx);
+// let show_completion_documentation = settings.show_completion_documentation;
-impl CopilotState {
- fn active_completion(&self) -> Option<&copilot::Completion> {
- self.completions.get(self.active_completion_index)
- }
+// let widest_completion_ix = self
+// .matches
+// .iter()
+// .enumerate()
+// .max_by_key(|(_, mat)| {
+// let completions = self.completions.read();
+// let completion = &completions[mat.candidate_id];
+// let documentation = &completion.documentation;
+
+// let mut len = completion.label.text.chars().count();
+// if let Some(Documentation::SingleLine(text)) = documentation {
+// if show_completion_documentation {
+// len += text.chars().count();
+// }
+// }
- fn text_for_active_completion(
- &self,
- cursor: Anchor,
- buffer: &MultiBufferSnapshot,
- ) -> Option<&str> {
- use language::ToOffset as _;
+// len
+// })
+// .map(|(ix, _)| ix);
- let completion = self.active_completion()?;
- let excerpt_id = self.excerpt_id?;
- let completion_buffer = buffer.buffer_for_excerpt(excerpt_id)?;
- if excerpt_id != cursor.excerpt_id
- || !completion.range.start.is_valid(completion_buffer)
- || !completion.range.end.is_valid(completion_buffer)
- {
- return None;
- }
+// let completions = self.completions.clone();
+// let matches = self.matches.clone();
+// let selected_item = self.selected_item;
- let mut completion_range = completion.range.to_offset(&completion_buffer);
- let prefix_len = Self::common_prefix(
- completion_buffer.chars_for_range(completion_range.clone()),
- completion.text.chars(),
- );
- completion_range.start += prefix_len;
- let suffix_len = Self::common_prefix(
- completion_buffer.reversed_chars_for_range(completion_range.clone()),
- completion.text[prefix_len..].chars().rev(),
- );
- completion_range.end = completion_range.end.saturating_sub(suffix_len);
+// let list = UniformList::new(self.list.clone(), matches.len(), cx, {
+// let style = style.clone();
+// move |_, range, items, cx| {
+// let start_ix = range.start;
+// let completions_guard = completions.read();
- if completion_range.is_empty()
- && completion_range.start == cursor.text_anchor.to_offset(&completion_buffer)
- {
- Some(&completion.text[prefix_len..completion.text.len() - suffix_len])
- } else {
- None
- }
- }
+// for (ix, mat) in matches[range].iter().enumerate() {
+// let item_ix = start_ix + ix;
+// let candidate_id = mat.candidate_id;
+// let completion = &completions_guard[candidate_id];
- fn cycle_completions(&mut self, direction: Direction) {
- match direction {
- Direction::Prev => {
- self.active_completion_index = if self.active_completion_index == 0 {
- self.completions.len().saturating_sub(1)
- } else {
- self.active_completion_index - 1
+// let documentation = if show_completion_documentation {
+// &completion.documentation
+// } else {
+// &None
+// };
+
+// items.push(
+// MouseEventHandler::new::<CompletionTag, _>(
+// mat.candidate_id,
+// cx,
+// |state, _| {
+// let item_style = if item_ix == selected_item {
+// style.autocomplete.selected_item
+// } else if state.hovered() {
+// style.autocomplete.hovered_item
+// } else {
+// style.autocomplete.item
+// };
+
+// let completion_label =
+// Text::new(completion.label.text.clone(), style.text.clone())
+// .with_soft_wrap(false)
+// .with_highlights(
+// combine_syntax_and_fuzzy_match_highlights(
+// &completion.label.text,
+// style.text.color.into(),
+// styled_runs_for_code_label(
+// &completion.label,
+// &style.syntax,
+// ),
+// &mat.positions,
+// ),
+// );
+
+// if let Some(Documentation::SingleLine(text)) = documentation {
+// Flex::row()
+// .with_child(completion_label)
+// .with_children((|| {
+// let text_style = TextStyle {
+// color: style.autocomplete.inline_docs_color,
+// font_size: style.text.font_size
+// * style.autocomplete.inline_docs_size_percent,
+// ..style.text.clone()
+// };
+
+// let label = Text::new(text.clone(), text_style)
+// .aligned()
+// .constrained()
+// .dynamically(move |constraint, _, _| {
+// gpui::SizeConstraint {
+// min: constraint.min,
+// max: vec2f(
+// constraint.max.x(),
+// constraint.min.y(),
+// ),
+// }
+// });
+
+// if Some(item_ix) == widest_completion_ix {
+// Some(
+// label
+// .contained()
+// .with_style(
+// style
+// .autocomplete
+// .inline_docs_container,
+// )
+// .into_any(),
+// )
+// } else {
+// Some(label.flex_float().into_any())
+// }
+// })())
+// .into_any()
+// } else {
+// completion_label.into_any()
+// }
+// .contained()
+// .with_style(item_style)
+// .constrained()
+// .dynamically(
+// move |constraint, _, _| {
+// if Some(item_ix) == widest_completion_ix {
+// constraint
+// } else {
+// gpui::SizeConstraint {
+// min: constraint.min,
+// max: constraint.min,
+// }
+// }
+// },
+// )
+// },
+// )
+// .with_cursor_style(CursorStyle::PointingHand)
+// .on_down(MouseButton::Left, move |_, this, cx| {
+// this.confirm_completion(
+// &ConfirmCompletion {
+// item_ix: Some(item_ix),
+// },
+// cx,
+// )
+// .map(|task| task.detach());
+// })
+// .constrained()
+// .with_min_width(style.autocomplete.completion_min_width)
+// .with_max_width(style.autocomplete.completion_max_width)
+// .into_any(),
+// );
+// }
+// }
+// })
+// .with_width_from_item(widest_completion_ix);
+
+// enum MultiLineDocumentation {}
+
+// Flex::row()
+// .with_child(list.flex(1., false))
+// .with_children({
+// let mat = &self.matches[selected_item];
+// let completions = self.completions.read();
+// let completion = &completions[mat.candidate_id];
+// let documentation = &completion.documentation;
+
+// match documentation {
+// Some(Documentation::MultiLinePlainText(text)) => Some(
+// Flex::column()
+// .scrollable::<MultiLineDocumentation>(0, None, cx)
+// .with_child(
+// Text::new(text.clone(), style.text.clone()).with_soft_wrap(true),
+// )
+// .contained()
+// .with_style(style.autocomplete.alongside_docs_container)
+// .constrained()
+// .with_max_width(style.autocomplete.alongside_docs_max_width)
+// .flex(1., false),
+// ),
+
+// Some(Documentation::MultiLineMarkdown(parsed)) => Some(
+// Flex::column()
+// .scrollable::<MultiLineDocumentation>(0, None, cx)
+// .with_child(render_parsed_markdown::<MultiLineDocumentation>(
+// parsed, &style, workspace, cx,
+// ))
+// .contained()
+// .with_style(style.autocomplete.alongside_docs_container)
+// .constrained()
+// .with_max_width(style.autocomplete.alongside_docs_max_width)
+// .flex(1., false),
+// ),
+
+// _ => None,
+// }
+// })
+// .contained()
+// .with_style(style.autocomplete.container)
+// .into_any()
+// }
+
+// pub async fn filter(&mut self, query: Option<&str>, executor: Arc<executor::Background>) {
+// let mut matches = if let Some(query) = query {
+// fuzzy::match_strings(
+// &self.match_candidates,
+// query,
+// query.chars().any(|c| c.is_uppercase()),
+// 100,
+// &Default::default(),
+// executor,
+// )
+// .await
+// } else {
+// self.match_candidates
+// .iter()
+// .enumerate()
+// .map(|(candidate_id, candidate)| StringMatch {
+// candidate_id,
+// score: Default::default(),
+// positions: Default::default(),
+// string: candidate.string.clone(),
+// })
+// .collect()
+// };
+
+// // Remove all candidates where the query's start does not match the start of any word in the candidate
+// if let Some(query) = query {
+// if let Some(query_start) = query.chars().next() {
+// matches.retain(|string_match| {
+// split_words(&string_match.string).any(|word| {
+// // Check that the first codepoint of the word as lowercase matches the first
+// // codepoint of the query as lowercase
+// word.chars()
+// .flat_map(|codepoint| codepoint.to_lowercase())
+// .zip(query_start.to_lowercase())
+// .all(|(word_cp, query_cp)| word_cp == query_cp)
+// })
+// });
+// }
+// }
+
+// let completions = self.completions.read();
+// matches.sort_unstable_by_key(|mat| {
+// let completion = &completions[mat.candidate_id];
+// (
+// completion.lsp_completion.sort_text.as_ref(),
+// Reverse(OrderedFloat(mat.score)),
+// completion.sort_key(),
+// )
+// });
+// drop(completions);
+
+// for mat in &mut matches {
+// let completions = self.completions.read();
+// let filter_start = completions[mat.candidate_id].label.filter_range.start;
+// for position in &mut mat.positions {
+// *position += filter_start;
+// }
+// }
+
+// self.matches = matches.into();
+// self.selected_item = 0;
+// }
+// }
+
+#[derive(Clone)]
+struct CodeActionsMenu {
+ actions: Arc<[CodeAction]>,
+ buffer: Model<Buffer>,
+ selected_item: usize,
+ // list: UniformListState,
+ deployed_from_indicator: bool,
+}
+
+// impl CodeActionsMenu {
+// fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
+// self.selected_item = 0;
+// self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+// cx.notify()
+// }
+
+// fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
+// if self.selected_item > 0 {
+// self.selected_item -= 1;
+// } else {
+// self.selected_item = self.actions.len() - 1;
+// }
+// self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+// cx.notify();
+// }
+
+// fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
+// if self.selected_item + 1 < self.actions.len() {
+// self.selected_item += 1;
+// } else {
+// self.selected_item = 0;
+// }
+// self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+// cx.notify();
+// }
+
+// fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
+// self.selected_item = self.actions.len() - 1;
+// self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+// cx.notify()
+// }
+
+// fn visible(&self) -> bool {
+// !self.actions.is_empty()
+// }
+
+// fn render(
+// &self,
+// mut cursor_position: DisplayPoint,
+// style: EditorStyle,
+// cx: &mut ViewContext<Editor>,
+// ) -> (DisplayPoint, AnyElement<Editor>) {
+// enum ActionTag {}
+
+// let container_style = style.autocomplete.container;
+// let actions = self.actions.clone();
+// let selected_item = self.selected_item;
+// let element = UniformList::new(
+// self.list.clone(),
+// actions.len(),
+// cx,
+// move |_, range, items, cx| {
+// let start_ix = range.start;
+// for (ix, action) in actions[range].iter().enumerate() {
+// let item_ix = start_ix + ix;
+// items.push(
+// MouseEventHandler::new::<ActionTag, _>(item_ix, cx, |state, _| {
+// let item_style = if item_ix == selected_item {
+// style.autocomplete.selected_item
+// } else if state.hovered() {
+// style.autocomplete.hovered_item
+// } else {
+// style.autocomplete.item
+// };
+
+// Text::new(action.lsp_action.title.clone(), style.text.clone())
+// .with_soft_wrap(false)
+// .contained()
+// .with_style(item_style)
+// })
+// .with_cursor_style(CursorStyle::PointingHand)
+// .on_down(MouseButton::Left, move |_, this, cx| {
+// let workspace = this
+// .workspace
+// .as_ref()
+// .and_then(|(workspace, _)| workspace.upgrade(cx));
+// cx.window_context().defer(move |cx| {
+// if let Some(workspace) = workspace {
+// workspace.update(cx, |workspace, cx| {
+// if let Some(task) = Editor::confirm_code_action(
+// workspace,
+// &ConfirmCodeAction {
+// item_ix: Some(item_ix),
+// },
+// cx,
+// ) {
+// task.detach_and_log_err(cx);
+// }
+// });
+// }
+// });
+// })
+// .into_any(),
+// );
+// }
+// },
+// )
+// .with_width_from_item(
+// self.actions
+// .iter()
+// .enumerate()
+// .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
+// .map(|(ix, _)| ix),
+// )
+// .contained()
+// .with_style(container_style)
+// .into_any();
+
+// if self.deployed_from_indicator {
+// *cursor_position.column_mut() = 0;
+// }
+
+// (cursor_position, element)
+// }
+// }
+
+pub struct CopilotState {
+ excerpt_id: Option<ExcerptId>,
+ pending_refresh: Task<Option<()>>,
+ pending_cycling_refresh: Task<Option<()>>,
+ cycled: bool,
+ completions: Vec<copilot::Completion>,
+ active_completion_index: usize,
+ suggestion: Option<Inlay>,
+}
+
+impl Default for CopilotState {
+ fn default() -> Self {
+ Self {
+ excerpt_id: None,
+ pending_cycling_refresh: Task::ready(Some(())),
+ pending_refresh: Task::ready(Some(())),
+ completions: Default::default(),
+ active_completion_index: 0,
+ cycled: false,
+ suggestion: None,
+ }
+ }
+}
+
+impl CopilotState {
+ fn active_completion(&self) -> Option<&copilot::Completion> {
+ self.completions.get(self.active_completion_index)
+ }
+
+ fn text_for_active_completion(
+ &self,
+ cursor: Anchor,
+ buffer: &MultiBufferSnapshot,
+ ) -> Option<&str> {
+ use language::ToOffset as _;
+
+ let completion = self.active_completion()?;
+ let excerpt_id = self.excerpt_id?;
+ let completion_buffer = buffer.buffer_for_excerpt(excerpt_id)?;
+ if excerpt_id != cursor.excerpt_id
+ || !completion.range.start.is_valid(completion_buffer)
+ || !completion.range.end.is_valid(completion_buffer)
+ {
+ return None;
+ }
+
+ let mut completion_range = completion.range.to_offset(&completion_buffer);
+ let prefix_len = Self::common_prefix(
+ completion_buffer.chars_for_range(completion_range.clone()),
+ completion.text.chars(),
+ );
+ completion_range.start += prefix_len;
+ let suffix_len = Self::common_prefix(
+ completion_buffer.reversed_chars_for_range(completion_range.clone()),
+ completion.text[prefix_len..].chars().rev(),
+ );
+ completion_range.end = completion_range.end.saturating_sub(suffix_len);
+
+ if completion_range.is_empty()
+ && completion_range.start == cursor.text_anchor.to_offset(&completion_buffer)
+ {
+ Some(&completion.text[prefix_len..completion.text.len() - suffix_len])
+ } else {
+ None
+ }
+ }
+
+ fn cycle_completions(&mut self, direction: Direction) {
+ match direction {
+ Direction::Prev => {
+ self.active_completion_index = if self.active_completion_index == 0 {
+ self.completions.len().saturating_sub(1)
+ } else {
+ self.active_completion_index - 1
};
}
Direction::Next => {
@@ -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:?}");
-
- 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(())
-}
+// 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(())
+// }
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?;
-
- // 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 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,
- );
- }
+// 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)
+// });
+
+// 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
+// }
+// });
+
+// 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);
- });
- })?;
-
- // 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?;
-
- // 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(())
-}
+// 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))
+// })??;
+
+// // 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(())
+// }
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
- }
-
- 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(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(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));
-
- 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);
- }
-
- 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 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 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;
- }
-
- 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);
-
- 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;
- }
- }
-
- 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);
- }
- }
-}
+// 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 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 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: 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,
+// );
+
+// self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
+// }
+
+// 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(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;
+// }
+
+// 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);
+// }
+
+// /// 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 let Some(visible_lines) = self.visible_line_count() {
+// if newest_head.row() < screen_top.row() + visible_lines as u32 {
+// return Ordering::Equal;
+// }
+// }
+
+// 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);
+// }
+// }
+// }
@@ -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<_>>();
-
- self.select_anchors(selections)
+ 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)
}
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,304 +17,304 @@ use util::{
test::{generate_marked_text, marked_text_ranges},
};
-use super::build_editor_with_project;
-
-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,
- }
- }
-
- 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 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 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<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 buffer_snapshot(&self) -> BufferSnapshot {
- self.buffer(|buffer, _| buffer.snapshot())
- }
-
- // pub fn simulate_keystroke(&mut self, keystroke_text: &str) -> ContextHandle {
- // let keystroke_under_test_handle =
- // self.add_assertion_context(format!("Simulated Keystroke: {:?}", keystroke_text));
- // let keystroke = Keystroke::parse(keystroke_text).unwrap();
-
- // self.cx.dispatch_keystroke(self.window, keystroke, false);
-
- // keystroke_under_test_handle
- // }
-
- // pub fn simulate_keystrokes<const COUNT: usize>(
- // &mut self,
- // keystroke_texts: [&str; COUNT],
- // ) -> ContextHandle {
- // let keystrokes_under_test_handle =
- // self.add_assertion_context(format!("Simulated Keystrokes: {:?}", keystroke_texts));
- // for keystroke_text in keystroke_texts.into_iter() {
- // self.simulate_keystroke(keystroke_text);
- // }
- // // it is common for keyboard shortcuts to kick off async actions, so this ensures that they are complete
- // // before returning.
- // // NOTE: we don't do this in simulate_keystroke() because a possible cause of bugs is that typing too
- // // quickly races with async actions.
- // if let Foreground::Deterministic { cx_id: _, executor } = self.cx.foreground().as_ref() {
- // executor.run_until_parked();
- // } else {
- // unreachable!();
- // }
-
- // 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 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)
- }
-
- 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
- // /// each selection.
- // ///
- // /// Returns a context handle so that assertion failures can print what
- // /// editor state was needed to cause the failure.
- // ///
- // /// See the `util::test::marked_text_ranges` function for more information.
- // pub fn set_state(&mut self, marked_text: &str) -> ContextHandle {
- // let state_context = self.add_assertion_context(format!(
- // "Initial Editor State: \"{}\"",
- // marked_text.escape_debug().to_string()
- // ));
- // let (unmarked_text, selection_ranges) = marked_text_ranges(marked_text, true);
- // self.editor.update(self.cx, |editor, cx| {
- // editor.set_text(unmarked_text, cx);
- // editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
- // s.select_ranges(selection_ranges)
- // })
- // });
- // state_context
- // }
-
- // /// Only change the editor's selections
- // pub fn set_selections_state(&mut self, marked_text: &str) -> ContextHandle {
- // let state_context = self.add_assertion_context(format!(
- // "Initial Editor State: \"{}\"",
- // marked_text.escape_debug().to_string()
- // ));
- // let (unmarked_text, selection_ranges) = marked_text_ranges(marked_text, true);
- // self.editor.update(self.cx, |editor, cx| {
- // assert_eq!(editor.text(cx), unmarked_text);
- // editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
- // s.select_ranges(selection_ranges)
- // })
- // });
- // state_context
- // }
-
- // /// Make an assertion about the editor's text and the ranges and directions
- // /// of its selections using a string containing embedded range markers.
- // ///
- // /// See the `util::test::marked_text_ranges` function for more information.
- // #[track_caller]
- // pub fn assert_editor_state(&mut self, marked_text: &str) {
- // let (unmarked_text, expected_selections) = marked_text_ranges(marked_text, true);
- // let buffer_text = self.buffer_text();
-
- // if buffer_text != unmarked_text {
- // panic!("Unmarked text doesn't match buffer text\nBuffer text: {buffer_text:?}\nUnmarked text: {unmarked_text:?}\nRaw buffer text\n{buffer_text}Raw unmarked text\n{unmarked_text}");
- // }
-
- // self.assert_selections(expected_selections, marked_text.to_string())
- // }
-
- // pub fn editor_state(&mut self) -> String {
- // generate_marked_text(self.buffer_text().as_str(), &self.editor_selections(), true)
- // }
-
- // #[track_caller]
- // pub fn assert_editor_background_highlights<Tag: 'static>(&mut self, marked_text: &str) {
- // let expected_ranges = self.ranges(marked_text);
- // let actual_ranges: Vec<Range<usize>> = self.update_editor(|editor, cx| {
- // let snapshot = editor.snapshot(cx);
- // editor
- // .background_highlights
- // .get(&TypeId::of::<Tag>())
- // .map(|h| h.1.clone())
- // .unwrap_or_default()
- // .into_iter()
- // .map(|range| range.to_offset(&snapshot.buffer_snapshot))
- // .collect()
- // });
- // assert_set_eq!(actual_ranges, expected_ranges);
- // }
-
- // #[track_caller]
- // pub fn assert_editor_text_highlights<Tag: ?Sized + 'static>(&mut self, marked_text: &str) {
- // let expected_ranges = self.ranges(marked_text);
- // let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
- // let actual_ranges: Vec<Range<usize>> = snapshot
- // .text_highlight_ranges::<Tag>()
- // .map(|ranges| ranges.as_ref().clone().1)
- // .unwrap_or_default()
- // .into_iter()
- // .map(|range| range.to_offset(&snapshot.buffer_snapshot))
- // .collect();
- // assert_set_eq!(actual_ranges, expected_ranges);
- // }
-
- // #[track_caller]
- // pub fn assert_editor_selections(&mut self, expected_selections: Vec<Range<usize>>) {
- // let expected_marked_text =
- // generate_marked_text(&self.buffer_text(), &expected_selections, true);
- // self.assert_selections(expected_selections, expected_marked_text)
- // }
-
- // fn editor_selections(&self) -> Vec<Range<usize>> {
- // self.editor
- // .read_with(self.cx, |editor, cx| editor.selections.all::<usize>(cx))
- // .into_iter()
- // .map(|s| {
- // if s.reversed {
- // s.end..s.start
- // } else {
- // s.start..s.end
- // }
- // })
- // .collect::<Vec<_>>()
- // }
-
- // #[track_caller]
- // fn assert_selections(
- // &mut self,
- // expected_selections: Vec<Range<usize>>,
- // expected_marked_text: String,
- // ) {
- // let actual_selections = self.editor_selections();
- // let actual_marked_text =
- // generate_marked_text(&self.buffer_text(), &actual_selections, true);
- // if expected_selections != actual_selections {
- // panic!(
- // indoc! {"
-
- // {}Editor has unexpected selections.
-
- // Expected selections:
- // {}
-
- // Actual selections:
- // {}
- // "},
- // self.assertion_context(),
- // expected_marked_text,
- // actual_marked_text,
- // );
- // }
- // }
-}
+// use super::build_editor_with_project;
+
+// 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,
+// }
+// }
+
+// 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.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 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 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 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 simulate_keystroke(&mut self, keystroke_text: &str) -> ContextHandle {
+// let keystroke_under_test_handle =
+// self.add_assertion_context(format!("Simulated Keystroke: {:?}", keystroke_text));
+// let keystroke = Keystroke::parse(keystroke_text).unwrap();
+
+// self.cx.dispatch_keystroke(self.window, keystroke, false);
+
+// keystroke_under_test_handle
+// }
+
+// pub fn simulate_keystrokes<const COUNT: usize>(
+// &mut self,
+// keystroke_texts: [&str; COUNT],
+// ) -> ContextHandle {
+// let keystrokes_under_test_handle =
+// self.add_assertion_context(format!("Simulated Keystrokes: {:?}", keystroke_texts));
+// for keystroke_text in keystroke_texts.into_iter() {
+// self.simulate_keystroke(keystroke_text);
+// }
+// // it is common for keyboard shortcuts to kick off async actions, so this ensures that they are complete
+// // before returning.
+// // NOTE: we don't do this in simulate_keystroke() because a possible cause of bugs is that typing too
+// // quickly races with async actions.
+// if let Foreground::Deterministic { cx_id: _, executor } = self.cx.foreground().as_ref() {
+// executor.run_until_parked();
+// } else {
+// unreachable!();
+// }
+
+// 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 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)
+// }
+
+// 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
+// /// each selection.
+// ///
+// /// Returns a context handle so that assertion failures can print what
+// /// editor state was needed to cause the failure.
+// ///
+// /// See the `util::test::marked_text_ranges` function for more information.
+// pub fn set_state(&mut self, marked_text: &str) -> ContextHandle {
+// let state_context = self.add_assertion_context(format!(
+// "Initial Editor State: \"{}\"",
+// marked_text.escape_debug().to_string()
+// ));
+// let (unmarked_text, selection_ranges) = marked_text_ranges(marked_text, true);
+// self.editor.update(self.cx, |editor, cx| {
+// editor.set_text(unmarked_text, cx);
+// editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
+// s.select_ranges(selection_ranges)
+// })
+// });
+// state_context
+// }
+
+// /// Only change the editor's selections
+// pub fn set_selections_state(&mut self, marked_text: &str) -> ContextHandle {
+// let state_context = self.add_assertion_context(format!(
+// "Initial Editor State: \"{}\"",
+// marked_text.escape_debug().to_string()
+// ));
+// let (unmarked_text, selection_ranges) = marked_text_ranges(marked_text, true);
+// self.editor.update(self.cx, |editor, cx| {
+// assert_eq!(editor.text(cx), unmarked_text);
+// editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
+// s.select_ranges(selection_ranges)
+// })
+// });
+// state_context
+// }
+
+// /// Make an assertion about the editor's text and the ranges and directions
+// /// of its selections using a string containing embedded range markers.
+// ///
+// /// See the `util::test::marked_text_ranges` function for more information.
+// #[track_caller]
+// pub fn assert_editor_state(&mut self, marked_text: &str) {
+// let (unmarked_text, expected_selections) = marked_text_ranges(marked_text, true);
+// let buffer_text = self.buffer_text();
+
+// if buffer_text != unmarked_text {
+// panic!("Unmarked text doesn't match buffer text\nBuffer text: {buffer_text:?}\nUnmarked text: {unmarked_text:?}\nRaw buffer text\n{buffer_text}Raw unmarked text\n{unmarked_text}");
+// }
+
+// self.assert_selections(expected_selections, marked_text.to_string())
+// }
+
+// pub fn editor_state(&mut self) -> String {
+// generate_marked_text(self.buffer_text().as_str(), &self.editor_selections(), true)
+// }
+
+// #[track_caller]
+// pub fn assert_editor_background_highlights<Tag: 'static>(&mut self, marked_text: &str) {
+// let expected_ranges = self.ranges(marked_text);
+// let actual_ranges: Vec<Range<usize>> = self.update_editor(|editor, cx| {
+// let snapshot = editor.snapshot(cx);
+// editor
+// .background_highlights
+// .get(&TypeId::of::<Tag>())
+// .map(|h| h.1.clone())
+// .unwrap_or_default()
+// .into_iter()
+// .map(|range| range.to_offset(&snapshot.buffer_snapshot))
+// .collect()
+// });
+// assert_set_eq!(actual_ranges, expected_ranges);
+// }
+
+// #[track_caller]
+// pub fn assert_editor_text_highlights<Tag: ?Sized + 'static>(&mut self, marked_text: &str) {
+// let expected_ranges = self.ranges(marked_text);
+// let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
+// let actual_ranges: Vec<Range<usize>> = snapshot
+// .text_highlight_ranges::<Tag>()
+// .map(|ranges| ranges.as_ref().clone().1)
+// .unwrap_or_default()
+// .into_iter()
+// .map(|range| range.to_offset(&snapshot.buffer_snapshot))
+// .collect();
+// assert_set_eq!(actual_ranges, expected_ranges);
+// }
+
+// #[track_caller]
+// pub fn assert_editor_selections(&mut self, expected_selections: Vec<Range<usize>>) {
+// let expected_marked_text =
+// generate_marked_text(&self.buffer_text(), &expected_selections, true);
+// self.assert_selections(expected_selections, expected_marked_text)
+// }
+
+// fn editor_selections(&self) -> Vec<Range<usize>> {
+// self.editor
+// .read_with(self.cx, |editor, cx| editor.selections.all::<usize>(cx))
+// .into_iter()
+// .map(|s| {
+// if s.reversed {
+// s.end..s.start
+// } else {
+// s.start..s.end
+// }
+// })
+// .collect::<Vec<_>>()
+// }
+
+// #[track_caller]
+// fn assert_selections(
+// &mut self,
+// expected_selections: Vec<Range<usize>>,
+// expected_marked_text: String,
+// ) {
+// let actual_selections = self.editor_selections();
+// let actual_marked_text =
+// generate_marked_text(&self.buffer_text(), &actual_selections, true);
+// if expected_selections != actual_selections {
+// panic!(
+// indoc! {"
+
+// {}Editor has unexpected selections.
+
+// Expected selections:
+// {}
+
+// Actual selections:
+// {}
+// "},
+// self.assertion_context(),
+// expected_marked_text,
+// actual_marked_text,
+// );
+// }
+// }
+// }
impl<'a> Deref for EditorTestContext<'a> {
type Target = gpui::TestAppContext;