#![allow(rustdoc::private_intra_doc_links)]//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.//! It comes in different flavors: single line, multiline and a fixed height one.//!//! Editor contains of multiple large submodules://! * [`element`] — the place where all rendering happens//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.//! Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.//!//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).//!//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behaviour.pub mod actions;mod blink_manager;pub mod display_map;mod editor_settings;mod element;mod inlay_hint_cache; mod debounced_delay;mod git;mod highlight_matching_bracket;mod hover_links;mod hover_popover;pub mod items;mod mouse_context_menu;pub mod movement;mod persistence;mod rust_analyzer_ext;pub mod scroll;mod selections_collection; #[cfg(test)]mod editor_tests;#[cfg(any(test, feature = "test-support"))]pub mod test;use ::git::diff::{DiffHunk, DiffHunkStatus};pub(crate) use actions::*;use aho_corasick::AhoCorasick;use anyhow::{anyhow, Context as _, Result};use blink_manager::BlinkManager;use client::{Collaborator, ParticipantIndex};use clock::ReplicaId;use collections::{hash_map, BTreeMap, Bound, HashMap, HashSet, VecDeque};use convert_case::{Case, Casing};use copilot::Copilot;use debounced_delay::DebouncedDelay;pub use display_map::DisplayPoint;use display_map::*;pub use editor_settings::EditorSettings;use element::LineWithInvisibles;pub use element::{ CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,};use futures::FutureExt;use fuzzy::{StringMatch, StringMatchCandidate};use git::diff_hunk_to_display;use gpui::{ div, impl_actions, point, prelude::*, px, relative, rems, size, uniform_list, Action, AnyElement, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context, DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusableView, FontId, FontStyle, FontWeight, HighlightStyle, Hsla, InteractiveText, KeyContext, Model, MouseButton, ParentElement, Pixels, Render, SharedString, StrikethroughStyle, Styled, StyledText, Subscription, Task, TextStyle, UnderlineStyle, UniformListScrollHandle, View, ViewContext, ViewInputHandler, VisualContext, WeakView, WhiteSpace, WindowContext,};use highlight_matching_bracket::refresh_matching_bracket_highlights;use hover_popover::{hide_hover, HoverState};use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};pub use items::MAX_TAB_TITLE_LEN;use itertools::Itertools;use language::{char_kind, CharKind};use language::{ language_settings::{self, all_language_settings, InlayHintSettings}, markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CodeAction, CodeLabel, Completion, CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId,}; use hover_links::{HoverLink, HoveredLinkState, InlayHighlight};use lsp::{DiagnosticSeverity, LanguageServerId};use mouse_context_menu::MouseContextMenu;use movement::TextLayoutDetails;use multi_buffer::ToOffsetUtf16;pub use multi_buffer::{ Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,};use ordered_float::OrderedFloat;use parking_lot::{Mutex, RwLock};use project::project_settings::{GitGutterSetting, ProjectSettings};use project::Item;use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction};use rand::prelude::*;use rpc::proto::*;use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};use serde::{Deserialize, Serialize};use settings::{Settings, SettingsStore};use smallvec::SmallVec;use snippet::Snippet;use std::ops::Not as _;use std::{ any::TypeId, borrow::Cow, cmp::{self, Ordering, Reverse}, mem, num::NonZeroU32, ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive}, path::Path, sync::Arc, time::{Duration, Instant},};pub use sum_tree::Bias;use text::{BufferId, OffsetUtf16, Rope};use theme::{ observe_buffer_font_size_adjustment, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,};use ui::{ h_flex, prelude::*, ButtonSize, ButtonStyle, IconButton, IconName, IconSize, ListItem, Popover, Tooltip,};use util::{maybe, post_inc, RangeExt, ResultExt, TryFutureExt};use workspace::Toast;use workspace::{ searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,}; use crate::hover_links::find_url; const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);const MAX_LINE_LEN: usize = 1024;const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;const MAX_SELECTION_HISTORY_LEN: usize = 1024;const COPILOT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);#[doc(hidden)]pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);#[doc(hidden)]pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75); pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(2); pub fn render_parsed_markdown( element_id: impl Into<ElementId>, parsed: &language::ParsedMarkdown, editor_style: &EditorStyle, workspace: Option<WeakView<Workspace>>, cx: &mut ViewContext<Editor>,) -> InteractiveText { let code_span_background_color = cx .theme() .colors() .editor_document_highlight_read_background; let highlights = gpui::combine_highlights( parsed.highlights.iter().filter_map(|(range, highlight)| { let highlight = highlight.to_highlight_style(&editor_style.syntax)?; Some((range.clone(), highlight)) }), parsed .regions .iter() .zip(&parsed.region_ranges) .filter_map(|(region, range)| { if region.code { Some(( range.clone(), HighlightStyle { background_color: Some(code_span_background_color), ..Default::default() }, )) } else { None } }), ); let mut links = Vec::new(); let mut link_ranges = Vec::new(); for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) { if let Some(link) = region.link.clone() { links.push(link); link_ranges.push(range.clone()); } } InteractiveText::new( element_id, StyledText::new(parsed.text.clone()).with_highlights(&editor_style.text, highlights), ) .on_click(link_ranges, move |clicked_range_ix, cx| { match &links[clicked_range_ix] { markdown::Link::Web { url } => cx.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(); }); } } } })} #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]pub(crate) enum InlayId { Suggestion(usize), Hint(usize),} impl InlayId { fn id(&self) -> usize { match self { Self::Suggestion(id) => *id, Self::Hint(id) => *id, } }} enum DocumentHighlightRead {}enum DocumentHighlightWrite {}enum InputComposition {} #[derive(Copy, Clone, PartialEq, Eq)]pub enum Direction { Prev, Next,} pub fn init_settings(cx: &mut AppContext) { EditorSettings::register(cx);} pub fn init(cx: &mut AppContext) { init_settings(cx); workspace::register_project_item::<Editor>(cx); workspace::register_followable_item::<Editor>(cx); workspace::register_deserializable_item::<Editor>(cx); cx.observe_new_views( |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| { workspace.register_action(Editor::new_file); workspace.register_action(Editor::new_file_in_direction); }, ) .detach(); cx.on_action(move |_: &workspace::NewFile, cx| { let app_state = workspace::AppState::global(cx); if let Some(app_state) = app_state.upgrade() { workspace::open_new(app_state, cx, |workspace, cx| { Editor::new_file(workspace, &Default::default(), cx) }) .detach(); } }); cx.on_action(move |_: &workspace::NewWindow, cx| { let app_state = workspace::AppState::global(cx); if let Some(app_state) = app_state.upgrade() { workspace::open_new(app_state, cx, |workspace, cx| { Editor::new_file(workspace, &Default::default(), cx) }) .detach(); } });} trait InvalidationRegion { fn ranges(&self) -> &[Range<Anchor>];} #[derive(Clone, Debug, PartialEq)]pub enum SelectPhase { Begin { position: DisplayPoint, add: bool, click_count: usize, }, BeginColumnar { position: DisplayPoint, goal_column: u32, }, Extend { position: DisplayPoint, click_count: usize, }, Update { position: DisplayPoint, goal_column: u32, scroll_delta: gpui::Point<f32>, }, End,} #[derive(Clone, Debug)]pub enum SelectMode { Character, Word(Range<Anchor>), Line(Range<Anchor>), All,} #[derive(Copy, Clone, PartialEq, Eq, Debug)]pub enum EditorMode { SingleLine, AutoHeight { max_lines: usize }, Full,} #[derive(Clone, Debug)]pub enum SoftWrap { None, EditorWidth, Column(u32),} #[derive(Clone)]pub struct EditorStyle { pub background: Hsla, pub local_player: PlayerColor, pub text: TextStyle, pub scrollbar_width: Pixels, pub syntax: Arc<SyntaxTheme>, pub status: StatusColors, pub inlay_hints_style: HighlightStyle, pub suggestions_style: HighlightStyle,} impl Default for EditorStyle { fn default() -> Self { Self { background: Hsla::default(), local_player: PlayerColor::default(), text: TextStyle::default(), scrollbar_width: Pixels::default(), syntax: Default::default(), // HACK: Status colors don't have a real default. // We should look into removing the status colors from the editor // style and retrieve them directly from the theme. status: StatusColors::dark(), inlay_hints_style: HighlightStyle::default(), suggestions_style: HighlightStyle::default(), } }} type CompletionId = usize; // type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>; type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<Range<Anchor>>); /// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`]////// See the [module level documentation](self) for more information.pub struct Editor { focus_handle: FocusHandle, /// The text buffer being edited buffer: Model<MultiBuffer>, /// Map of how text in the buffer should be displayed. /// Handles soft wraps, folds, fake inlay text insertions, etc. pub display_map: Model<DisplayMap>, pub selections: SelectionsCollection, pub scroll_manager: ScrollManager, columnar_selection_tail: Option<Anchor>, add_selections_state: Option<AddSelectionsState>, select_next_state: Option<SelectNextState>, select_prev_state: Option<SelectNextState>, selection_history: SelectionHistory, autoclose_regions: Vec<AutocloseRegion>, snippet_stack: InvalidationStack<SnippetState>, select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>, ime_transaction: Option<TransactionId>, active_diagnostics: Option<ActiveDiagnosticGroup>, soft_wrap_mode_override: Option<language_settings::SoftWrap>, project: Option<Model<Project>>, completion_provider: Option<Box<dyn CompletionProvider>>, collaboration_hub: Option<Box<dyn CollaborationHub>>, blink_manager: Model<BlinkManager>, show_cursor_names: bool, hovered_cursors: HashMap<HoveredCursor, Task<()>>, pub show_local_selections: bool, mode: EditorMode, show_breadcrumbs: bool, show_gutter: bool, show_wrap_guides: Option<bool>, placeholder_text: Option<Arc<str>>, highlight_order: usize, highlighted_rows: HashMap<TypeId, Vec<(usize, Range<Anchor>, Hsla)>>, background_highlights: BTreeMap<TypeId, BackgroundHighlight>, nav_history: Option<ItemNavHistory>, context_menu: RwLock<Option<ContextMenu>>, mouse_context_menu: Option<MouseContextMenu>, completion_tasks: Vec<(CompletionId, Task<Option<()>>)>, find_all_references_task_sources: Vec<Anchor>, next_completion_id: CompletionId, completion_documentation_pre_resolve_debounce: DebouncedDelay, available_code_actions: Option<(Model<Buffer>, Arc<[CodeAction]>)>, code_actions_task: Option<Task<()>>, document_highlights_task: Option<Task<()>>, pending_rename: Option<RenameState>, searchable: bool, cursor_shape: CursorShape, collapse_matches: bool, autoindent_mode: Option<AutoindentMode>, workspace: Option<(WeakView<Workspace>, WorkspaceId)>, keymap_context_layers: BTreeMap<TypeId, KeyContext>, input_enabled: bool, use_modal_editing: bool, read_only: bool, leader_peer_id: Option<PeerId>, remote_id: Option<ViewId>, hover_state: HoverState, gutter_hovered: bool, hovered_link_state: Option<HoveredLinkState>, copilot_state: CopilotState, inlay_hint_cache: InlayHintCache, next_inlay_id: usize, _subscriptions: Vec<Subscription>, pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>, gutter_width: Pixels, pub vim_replace_map: HashMap<Range<usize>, String>, style: Option<EditorStyle>, editor_actions: Vec<Box<dyn Fn(&mut ViewContext<Self>)>>, show_copilot_suggestions: bool, use_autoclose: bool, auto_replace_emoji_shortcode: bool, custom_context_menu: Option< Box< dyn 'static + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>, >, >,} pub struct EditorSnapshot { pub mode: EditorMode, show_gutter: bool, pub display_snapshot: DisplaySnapshot, pub placeholder_text: Option<Arc<str>>, is_focused: bool, scroll_anchor: ScrollAnchor, ongoing_scroll: OngoingScroll,} pub struct GutterDimensions { pub left_padding: Pixels, pub right_padding: Pixels, pub width: Pixels, pub margin: Pixels,} impl Default for GutterDimensions { fn default() -> Self { Self { left_padding: Pixels::ZERO, right_padding: Pixels::ZERO, width: Pixels::ZERO, margin: Pixels::ZERO, } }} #[derive(Debug)]pub struct RemoteSelection { pub replica_id: ReplicaId, pub selection: Selection<Anchor>, pub cursor_shape: CursorShape, pub peer_id: PeerId, pub line_mode: bool, pub participant_index: Option<ParticipantIndex>, pub user_name: Option<SharedString>,} #[derive(Clone, Debug)]struct SelectionHistoryEntry { selections: Arc<[Selection<Anchor>]>, select_next_state: Option<SelectNextState>, select_prev_state: Option<SelectNextState>, add_selections_state: Option<AddSelectionsState>,} enum SelectionHistoryMode { Normal, Undoing, Redoing,} #[derive(Clone, PartialEq, Eq, Hash)]struct HoveredCursor { replica_id: u16, selection_id: usize,} Lines 1–500 of 10799. Load more
#![allow(rustdoc::private_intra_doc_links)] //! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise). //! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element. //! It comes in different flavors: single line, multiline and a fixed height one. //! //! Editor contains of multiple large submodules: //! * [`element`] — the place where all rendering happens //! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them. //! Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.). //! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly. //! //! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s). //! //! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behaviour. pub mod actions; mod blink_manager; pub mod display_map; mod editor_settings; mod element; mod inlay_hint_cache; mod debounced_delay; mod git; mod highlight_matching_bracket; mod hover_links; mod hover_popover; pub mod items; mod mouse_context_menu; pub mod movement; mod persistence; mod rust_analyzer_ext; pub mod scroll; mod selections_collection; #[cfg(test)] mod editor_tests; #[cfg(any(test, feature = "test-support"))] pub mod test; use ::git::diff::{DiffHunk, DiffHunkStatus}; pub(crate) use actions::*; use aho_corasick::AhoCorasick; use anyhow::{anyhow, Context as _, Result}; use blink_manager::BlinkManager; use client::{Collaborator, ParticipantIndex}; use clock::ReplicaId; use collections::{hash_map, BTreeMap, Bound, HashMap, HashSet, VecDeque}; use convert_case::{Case, Casing}; use copilot::Copilot; use debounced_delay::DebouncedDelay; pub use display_map::DisplayPoint; use display_map::*; pub use editor_settings::EditorSettings; use element::LineWithInvisibles; pub use element::{ CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition, }; use futures::FutureExt; use fuzzy::{StringMatch, StringMatchCandidate}; use git::diff_hunk_to_display; use gpui::{ div, impl_actions, point, prelude::*, px, relative, rems, size, uniform_list, Action, AnyElement, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context, DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusableView, FontId, FontStyle, FontWeight, HighlightStyle, Hsla, InteractiveText, KeyContext, Model, MouseButton, ParentElement, Pixels, Render, SharedString, StrikethroughStyle, Styled, StyledText, Subscription, Task, TextStyle, UnderlineStyle, UniformListScrollHandle, View, ViewContext, ViewInputHandler, VisualContext, WeakView, WhiteSpace, WindowContext, }; use highlight_matching_bracket::refresh_matching_bracket_highlights; use hover_popover::{hide_hover, HoverState}; use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy}; pub use items::MAX_TAB_TITLE_LEN; use itertools::Itertools; use language::{char_kind, CharKind}; use language::{ language_settings::{self, all_language_settings, InlayHintSettings}, markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CodeAction, CodeLabel, Completion, CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId, }; use hover_links::{HoverLink, HoveredLinkState, InlayHighlight}; use lsp::{DiagnosticSeverity, LanguageServerId}; use mouse_context_menu::MouseContextMenu; use movement::TextLayoutDetails; use multi_buffer::ToOffsetUtf16; pub use multi_buffer::{ Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint, }; use ordered_float::OrderedFloat; use parking_lot::{Mutex, RwLock}; use project::project_settings::{GitGutterSetting, ProjectSettings}; use project::Item; use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction}; use rand::prelude::*; use rpc::proto::*; use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide}; use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection}; use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsStore}; use smallvec::SmallVec; use snippet::Snippet; use std::ops::Not as _; use std::{ any::TypeId, borrow::Cow, cmp::{self, Ordering, Reverse}, mem, num::NonZeroU32, ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive}, path::Path, sync::Arc, time::{Duration, Instant}, }; pub use sum_tree::Bias; use text::{BufferId, OffsetUtf16, Rope}; use theme::{ observe_buffer_font_size_adjustment, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings, }; use ui::{ h_flex, prelude::*, ButtonSize, ButtonStyle, IconButton, IconName, IconSize, ListItem, Popover, Tooltip, }; use util::{maybe, post_inc, RangeExt, ResultExt, TryFutureExt}; use workspace::Toast; use workspace::{ searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId, }; use crate::hover_links::find_url; const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); const MAX_LINE_LEN: usize = 1024; const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10; const MAX_SELECTION_HISTORY_LEN: usize = 1024; const COPILOT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75); pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000); #[doc(hidden)] pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250); #[doc(hidden)] pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75); pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(2); pub fn render_parsed_markdown( element_id: impl Into<ElementId>, parsed: &language::ParsedMarkdown, editor_style: &EditorStyle, workspace: Option<WeakView<Workspace>>, cx: &mut ViewContext<Editor>, ) -> InteractiveText { let code_span_background_color = cx .theme() .colors() .editor_document_highlight_read_background; let highlights = gpui::combine_highlights( parsed.highlights.iter().filter_map(|(range, highlight)| { let highlight = highlight.to_highlight_style(&editor_style.syntax)?; Some((range.clone(), highlight)) }), parsed .regions .iter() .zip(&parsed.region_ranges) .filter_map(|(region, range)| { if region.code { Some(( range.clone(), HighlightStyle { background_color: Some(code_span_background_color), ..Default::default() }, )) } else { None } }), ); let mut links = Vec::new(); let mut link_ranges = Vec::new(); for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) { if let Some(link) = region.link.clone() { links.push(link); link_ranges.push(range.clone()); } } InteractiveText::new( element_id, StyledText::new(parsed.text.clone()).with_highlights(&editor_style.text, highlights), ) .on_click(link_ranges, move |clicked_range_ix, cx| { match &links[clicked_range_ix] { markdown::Link::Web { url } => cx.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(); }); } } } }) } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) enum InlayId { Suggestion(usize), Hint(usize), } impl InlayId { fn id(&self) -> usize { match self { Self::Suggestion(id) => *id, Self::Hint(id) => *id, } } } enum DocumentHighlightRead {} enum DocumentHighlightWrite {} enum InputComposition {} #[derive(Copy, Clone, PartialEq, Eq)] pub enum Direction { Prev, Next, } pub fn init_settings(cx: &mut AppContext) { EditorSettings::register(cx); } pub fn init(cx: &mut AppContext) { init_settings(cx); workspace::register_project_item::<Editor>(cx); workspace::register_followable_item::<Editor>(cx); workspace::register_deserializable_item::<Editor>(cx); cx.observe_new_views( |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| { workspace.register_action(Editor::new_file); workspace.register_action(Editor::new_file_in_direction); }, ) .detach(); cx.on_action(move |_: &workspace::NewFile, cx| { let app_state = workspace::AppState::global(cx); if let Some(app_state) = app_state.upgrade() { workspace::open_new(app_state, cx, |workspace, cx| { Editor::new_file(workspace, &Default::default(), cx) }) .detach(); } }); cx.on_action(move |_: &workspace::NewWindow, cx| { let app_state = workspace::AppState::global(cx); if let Some(app_state) = app_state.upgrade() { workspace::open_new(app_state, cx, |workspace, cx| { Editor::new_file(workspace, &Default::default(), cx) }) .detach(); } }); } trait InvalidationRegion { fn ranges(&self) -> &[Range<Anchor>]; } #[derive(Clone, Debug, PartialEq)] pub enum SelectPhase { Begin { position: DisplayPoint, add: bool, click_count: usize, }, BeginColumnar { position: DisplayPoint, goal_column: u32, }, Extend { position: DisplayPoint, click_count: usize, }, Update { position: DisplayPoint, goal_column: u32, scroll_delta: gpui::Point<f32>, }, End, } #[derive(Clone, Debug)] pub enum SelectMode { Character, Word(Range<Anchor>), Line(Range<Anchor>), All, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum EditorMode { SingleLine, AutoHeight { max_lines: usize }, Full, } #[derive(Clone, Debug)] pub enum SoftWrap { None, EditorWidth, Column(u32), } #[derive(Clone)] pub struct EditorStyle { pub background: Hsla, pub local_player: PlayerColor, pub text: TextStyle, pub scrollbar_width: Pixels, pub syntax: Arc<SyntaxTheme>, pub status: StatusColors, pub inlay_hints_style: HighlightStyle, pub suggestions_style: HighlightStyle, } impl Default for EditorStyle { fn default() -> Self { Self { background: Hsla::default(), local_player: PlayerColor::default(), text: TextStyle::default(), scrollbar_width: Pixels::default(), syntax: Default::default(), // HACK: Status colors don't have a real default. // We should look into removing the status colors from the editor // style and retrieve them directly from the theme. status: StatusColors::dark(), inlay_hints_style: HighlightStyle::default(), suggestions_style: HighlightStyle::default(), } } } type CompletionId = usize; // type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor; // type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>; type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<Range<Anchor>>); /// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`] /// /// See the [module level documentation](self) for more information. pub struct Editor { focus_handle: FocusHandle, /// The text buffer being edited buffer: Model<MultiBuffer>, /// Map of how text in the buffer should be displayed. /// Handles soft wraps, folds, fake inlay text insertions, etc. pub display_map: Model<DisplayMap>, pub selections: SelectionsCollection, pub scroll_manager: ScrollManager, columnar_selection_tail: Option<Anchor>, add_selections_state: Option<AddSelectionsState>, select_next_state: Option<SelectNextState>, select_prev_state: Option<SelectNextState>, selection_history: SelectionHistory, autoclose_regions: Vec<AutocloseRegion>, snippet_stack: InvalidationStack<SnippetState>, select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>, ime_transaction: Option<TransactionId>, active_diagnostics: Option<ActiveDiagnosticGroup>, soft_wrap_mode_override: Option<language_settings::SoftWrap>, project: Option<Model<Project>>, completion_provider: Option<Box<dyn CompletionProvider>>, collaboration_hub: Option<Box<dyn CollaborationHub>>, blink_manager: Model<BlinkManager>, show_cursor_names: bool, hovered_cursors: HashMap<HoveredCursor, Task<()>>, pub show_local_selections: bool, mode: EditorMode, show_breadcrumbs: bool, show_gutter: bool, show_wrap_guides: Option<bool>, placeholder_text: Option<Arc<str>>, highlight_order: usize, highlighted_rows: HashMap<TypeId, Vec<(usize, Range<Anchor>, Hsla)>>, background_highlights: BTreeMap<TypeId, BackgroundHighlight>, nav_history: Option<ItemNavHistory>, context_menu: RwLock<Option<ContextMenu>>, mouse_context_menu: Option<MouseContextMenu>, completion_tasks: Vec<(CompletionId, Task<Option<()>>)>, find_all_references_task_sources: Vec<Anchor>, next_completion_id: CompletionId, completion_documentation_pre_resolve_debounce: DebouncedDelay, available_code_actions: Option<(Model<Buffer>, Arc<[CodeAction]>)>, code_actions_task: Option<Task<()>>, document_highlights_task: Option<Task<()>>, pending_rename: Option<RenameState>, searchable: bool, cursor_shape: CursorShape, collapse_matches: bool, autoindent_mode: Option<AutoindentMode>, workspace: Option<(WeakView<Workspace>, WorkspaceId)>, keymap_context_layers: BTreeMap<TypeId, KeyContext>, input_enabled: bool, use_modal_editing: bool, read_only: bool, leader_peer_id: Option<PeerId>, remote_id: Option<ViewId>, hover_state: HoverState, gutter_hovered: bool, hovered_link_state: Option<HoveredLinkState>, copilot_state: CopilotState, inlay_hint_cache: InlayHintCache, next_inlay_id: usize, _subscriptions: Vec<Subscription>, pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>, gutter_width: Pixels, pub vim_replace_map: HashMap<Range<usize>, String>, style: Option<EditorStyle>, editor_actions: Vec<Box<dyn Fn(&mut ViewContext<Self>)>>, show_copilot_suggestions: bool, use_autoclose: bool, auto_replace_emoji_shortcode: bool, custom_context_menu: Option< Box< dyn 'static + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>, >, >, } pub struct EditorSnapshot { pub mode: EditorMode, show_gutter: bool, pub display_snapshot: DisplaySnapshot, pub placeholder_text: Option<Arc<str>>, is_focused: bool, scroll_anchor: ScrollAnchor, ongoing_scroll: OngoingScroll, } pub struct GutterDimensions { pub left_padding: Pixels, pub right_padding: Pixels, pub width: Pixels, pub margin: Pixels, } impl Default for GutterDimensions { fn default() -> Self { Self { left_padding: Pixels::ZERO, right_padding: Pixels::ZERO, width: Pixels::ZERO, margin: Pixels::ZERO, } } } #[derive(Debug)] pub struct RemoteSelection { pub replica_id: ReplicaId, pub selection: Selection<Anchor>, pub cursor_shape: CursorShape, pub peer_id: PeerId, pub line_mode: bool, pub participant_index: Option<ParticipantIndex>, pub user_name: Option<SharedString>, } #[derive(Clone, Debug)] struct SelectionHistoryEntry { selections: Arc<[Selection<Anchor>]>, select_next_state: Option<SelectNextState>, select_prev_state: Option<SelectNextState>, add_selections_state: Option<AddSelectionsState>, } enum SelectionHistoryMode { Normal, Undoing, Redoing, } #[derive(Clone, PartialEq, Eq, Hash)] struct HoveredCursor { replica_id: u16, selection_id: usize, }