#![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 behavior.pub mod actions;mod blink_manager;mod clangd_ext;pub mod code_context_menus;pub mod display_map;mod editor_settings;mod editor_settings_controls;mod element;mod git;mod highlight_matching_bracket;mod hover_links;pub mod hover_popover;mod indent_guides;mod inlay_hint_cache;pub mod items;mod jsx_tag_auto_close;mod linked_editing_ranges;mod lsp_colors;mod lsp_ext;mod mouse_context_menu;pub mod movement;mod persistence;mod proposed_changes_editor;mod rust_analyzer_ext;pub mod scroll;mod selections_collection;pub mod tasks; #[cfg(test)]mod code_completion_tests;#[cfg(test)]mod edit_prediction_tests;#[cfg(test)]mod editor_tests;mod signature_help;#[cfg(any(test, feature = "test-support"))]pub mod test; pub(crate) use actions::*;pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};pub use edit_prediction::Direction;pub use editor_settings::{ CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,};pub use editor_settings_controls::*;pub use element::{ CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,};pub use git::blame::BlameRenderer;pub use hover_popover::hover_markdown_style;pub use items::MAX_TAB_TITLE_LEN;pub use lsp::CompletionContext;pub use lsp_ext::lsp_tasks;pub use multi_buffer::{ Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey, RowInfo, ToOffset, ToPoint,};pub use proposed_changes_editor::{ ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,};pub use text::Bias; use ::git::{ Restore, blame::{BlameEntry, ParsedCommitMessage},};use aho_corasick::AhoCorasick;use anyhow::{Context as _, Result, anyhow};use blink_manager::BlinkManager;use buffer_diff::DiffHunkStatus;use client::{Collaborator, ParticipantIndex};use clock::{AGENT_REPLICA_ID, ReplicaId};use code_context_menus::{ AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu, CompletionsMenu, ContextMenuOrigin,};use collections::{BTreeMap, HashMap, HashSet, VecDeque};use convert_case::{Case, Casing};use dap::TelemetrySpawnLocation;use display_map::*;use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};use futures::{ FutureExt, StreamExt as _, future::{self, Shared, join}, stream::FuturesUnordered,};use fuzzy::{StringMatch, StringMatchCandidate};use git::blame::{GitBlame, GlobalBlameRenderer};use gpui::{ Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext, AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context, DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers, MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative, size,};use highlight_matching_bracket::refresh_matching_bracket_highlights;use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};use hover_popover::{HoverState, hide_hover};use indent_guides::ActiveIndentGuidesState;use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};use itertools::{Either, Itertools};use language::{ AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow, BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery, language_settings::{ self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings, language_settings, }, point_from_lsp, point_to_lsp, text_diff_with_options,};use linked_editing_ranges::refresh_linked_ranges;use lsp::{ CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode, LanguageServerId,};use lsp_colors::LspColorData;use markdown::Markdown;use mouse_context_menu::MouseContextMenu;use movement::TextLayoutDetails;use multi_buffer::{ ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow, MultiOrSingleBufferOffsetRange, ToOffsetUtf16,};use parking_lot::Mutex;use persistence::DB;use project::{ BreakpointWithPosition, CodeAction, Completion, CompletionIntent, CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind, debugger::breakpoint_store::Breakpoint, debugger::{ breakpoint_store::{ BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore, BreakpointStoreEvent, }, session::{Session, SessionEvent}, }, git_store::{GitStoreEvent, RepositoryEvent}, lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle}, project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter}, project_settings::{GitGutterSetting, ProjectSettings},};use rand::{seq::SliceRandom, thread_rng};use rpc::{ErrorCode, ErrorExt, proto::PeerId};use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};use selections_collection::{ MutableSelectionsCollection, SelectionsCollection, resolve_selections,};use serde::{Deserialize, Serialize};use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};use smallvec::{SmallVec, smallvec};use snippet::Snippet;use std::{ any::TypeId, borrow::Cow, cell::OnceCell, cell::RefCell, cmp::{self, Ordering, Reverse}, iter::Peekable, mem, num::NonZeroU32, ops::Not, ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive}, path::{Path, PathBuf}, rc::Rc, sync::Arc, time::{Duration, Instant},};use sum_tree::TreeMap;use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};use text::{BufferId, FromAnchor, OffsetUtf16, Rope};use theme::{ ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings, observe_buffer_font_size_adjustment,};use ui::{ ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,};use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};use workspace::{ CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings, item::{ItemHandle, PreviewTabsSettings, SaveOptions}, notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt}, searchable::SearchEvent,}; use crate::{ code_context_menus::CompletionsMenuSource, editor_settings::MultiCursorModifier, hover_links::{find_url, find_url_from_range}, signature_help::{SignatureHelpHiddenBy, SignatureHelpState},}; pub const FILE_HEADER_HEIGHT: u32 = 2;pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;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;pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);#[doc(hidden)]pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100); pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1); pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.)); pub type RenderDiffHunkControlsFn = Arc< dyn Fn( u32, &DiffHunkStatus, Range<Anchor>, bool, Pixels, &Entity<Editor>, &mut Window, &mut App, ) -> AnyElement,>; enum ReportEditorEvent { Saved { auto_saved: bool }, EditorOpened, ZetaTosClicked, Closed,} impl ReportEditorEvent { pub fn event_type(&self) -> &'static str { match self { Self::Saved { .. } => "Editor Saved", Self::EditorOpened => "Editor Opened", Self::ZetaTosClicked => "Edit Prediction Provider ToS Clicked", Self::Closed => "Editor Closed", } }} struct InlineValueCache { enabled: bool, inlays: Vec<InlayId>, refresh_task: Task<Option<()>>,} impl InlineValueCache { fn new(enabled: bool) -> Self { Self { enabled, inlays: Vec::new(), refresh_task: Task::ready(None), } }} #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]pub enum InlayId { EditPrediction(usize), DebuggerValue(usize), // LSP Hint(usize), Color(usize),} impl InlayId { fn id(&self) -> usize { match self { Self::EditPrediction(id) => *id, Self::DebuggerValue(id) => *id, Self::Hint(id) => *id, Self::Color(id) => *id, } }} pub enum ActiveDebugLine {}pub enum DebugStackFrameLine {}enum DocumentHighlightRead {}enum DocumentHighlightWrite {}enum InputComposition {}pub enum PendingInput {}enum SelectedTextHighlight {} pub enum ConflictsOuter {}pub enum ConflictsOurs {}pub enum ConflictsTheirs {}pub enum ConflictsOursMarker {}pub enum ConflictsTheirsMarker {} #[derive(Debug, Copy, Clone, PartialEq, Eq)]pub enum Navigated { Yes, No,} impl Navigated { pub fn from_bool(yes: bool) -> Navigated { if yes { Navigated::Yes } else { Navigated::No } }} #[derive(Debug, Clone, PartialEq, Eq)]enum DisplayDiffHunk { Folded { display_row: DisplayRow, }, Unfolded { is_created_file: bool, diff_base_byte_range: Range<usize>, display_row_range: Range<DisplayRow>, multi_buffer_range: Range<Anchor>, status: DiffHunkStatus, },} pub enum HideMouseCursorOrigin { TypingAction, MovementAction,} pub fn init_settings(cx: &mut App) { EditorSettings::register(cx);} pub fn init(cx: &mut App) { init_settings(cx); cx.set_global(GlobalBlameRenderer(Arc::new(()))); workspace::register_project_item::<Editor>(cx); workspace::FollowableViewRegistry::register::<Editor>(cx); workspace::register_serializable_item::<Editor>(cx); cx.observe_new( |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| { workspace.register_action(Editor::new_file); workspace.register_action(Editor::new_file_vertical); workspace.register_action(Editor::new_file_horizontal); workspace.register_action(Editor::cancel_language_server_work); workspace.register_action(Editor::toggle_focus); }, ) .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( Default::default(), app_state, cx, |workspace, window, cx| { Editor::new_file(workspace, &Default::default(), window, 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( Default::default(), app_state, cx, |workspace, window, cx| { cx.activate(true); Editor::new_file(workspace, &Default::default(), window, cx) }, ) .detach(); } });} pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) { cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));} pub trait DiagnosticRenderer { fn render_group( &self, diagnostic_group: Vec<DiagnosticEntry<Point>>, buffer_id: BufferId, snapshot: EditorSnapshot, editor: WeakEntity<Editor>, cx: &mut App, ) -> Vec<BlockProperties<Anchor>>; fn render_hover( &self, diagnostic_group: Vec<DiagnosticEntry<Point>>, range: Range<Point>, buffer_id: BufferId, cx: &mut App, ) -> Option<Entity<markdown::Markdown>>; fn open_link( &self, editor: &mut Editor, link: SharedString, window: &mut Window, cx: &mut Context<Editor>, );} pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>); impl GlobalDiagnosticRenderer { fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> { cx.try_global::<Self>().map(|g| g.0.clone()) }} impl gpui::Global for GlobalDiagnosticRenderer {}pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) { cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));} pub struct SearchWithinRange; 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, reset: bool, mode: ColumnarMode, goal_column: u32, }, Extend { position: DisplayPoint, click_count: usize, }, Update { position: DisplayPoint, goal_column: u32, scroll_delta: gpui::Point<f32>, }, End,} #[derive(Clone, Debug, PartialEq)]pub enum ColumnarMode { FromMouse, FromSelection,} #[derive(Clone, Debug)]pub enum SelectMode { Character, Word(Range<Anchor>), Line(Range<Anchor>), All,} #[derive(Clone, PartialEq, Eq, Debug)]pub enum EditorMode { SingleLine, AutoHeight { min_lines: usize,Lines 1–500 of 23973. 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 behavior. pub mod actions; mod blink_manager; mod clangd_ext; pub mod code_context_menus; pub mod display_map; mod editor_settings; mod editor_settings_controls; mod element; mod git; mod highlight_matching_bracket; mod hover_links; pub mod hover_popover; mod indent_guides; mod inlay_hint_cache; pub mod items; mod jsx_tag_auto_close; mod linked_editing_ranges; mod lsp_colors; mod lsp_ext; mod mouse_context_menu; pub mod movement; mod persistence; mod proposed_changes_editor; mod rust_analyzer_ext; pub mod scroll; mod selections_collection; pub mod tasks; #[cfg(test)] mod code_completion_tests; #[cfg(test)] mod edit_prediction_tests; #[cfg(test)] mod editor_tests; mod signature_help; #[cfg(any(test, feature = "test-support"))] pub mod test; pub(crate) use actions::*; pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder}; pub use edit_prediction::Direction; pub use editor_settings::{ CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar, }; pub use editor_settings_controls::*; pub use element::{ CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition, }; pub use git::blame::BlameRenderer; pub use hover_popover::hover_markdown_style; pub use items::MAX_TAB_TITLE_LEN; pub use lsp::CompletionContext; pub use lsp_ext::lsp_tasks; pub use multi_buffer::{ Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey, RowInfo, ToOffset, ToPoint, }; pub use proposed_changes_editor::{ ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar, }; pub use text::Bias; use ::git::{ Restore, blame::{BlameEntry, ParsedCommitMessage}, }; use aho_corasick::AhoCorasick; use anyhow::{Context as _, Result, anyhow}; use blink_manager::BlinkManager; use buffer_diff::DiffHunkStatus; use client::{Collaborator, ParticipantIndex}; use clock::{AGENT_REPLICA_ID, ReplicaId}; use code_context_menus::{ AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu, CompletionsMenu, ContextMenuOrigin, }; use collections::{BTreeMap, HashMap, HashSet, VecDeque}; use convert_case::{Case, Casing}; use dap::TelemetrySpawnLocation; use display_map::*; use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle}; use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings}; use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line}; use futures::{ FutureExt, StreamExt as _, future::{self, Shared, join}, stream::FuturesUnordered, }; use fuzzy::{StringMatch, StringMatchCandidate}; use git::blame::{GitBlame, GlobalBlameRenderer}; use gpui::{ Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext, AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context, DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers, MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative, size, }; use highlight_matching_bracket::refresh_matching_bracket_highlights; use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file}; use hover_popover::{HoverState, hide_hover}; use indent_guides::ActiveIndentGuidesState; use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy}; use itertools::{Either, Itertools}; use language::{ AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow, BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery, language_settings::{ self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings, language_settings, }, point_from_lsp, point_to_lsp, text_diff_with_options, }; use linked_editing_ranges::refresh_linked_ranges; use lsp::{ CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode, LanguageServerId, }; use lsp_colors::LspColorData; use markdown::Markdown; use mouse_context_menu::MouseContextMenu; use movement::TextLayoutDetails; use multi_buffer::{ ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow, MultiOrSingleBufferOffsetRange, ToOffsetUtf16, }; use parking_lot::Mutex; use persistence::DB; use project::{ BreakpointWithPosition, CodeAction, Completion, CompletionIntent, CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind, debugger::breakpoint_store::Breakpoint, debugger::{ breakpoint_store::{ BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore, BreakpointStoreEvent, }, session::{Session, SessionEvent}, }, git_store::{GitStoreEvent, RepositoryEvent}, lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle}, project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter}, project_settings::{GitGutterSetting, ProjectSettings}, }; use rand::{seq::SliceRandom, thread_rng}; use rpc::{ErrorCode, ErrorExt, proto::PeerId}; use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide}; use selections_collection::{ MutableSelectionsCollection, SelectionsCollection, resolve_selections, }; use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file}; use smallvec::{SmallVec, smallvec}; use snippet::Snippet; use std::{ any::TypeId, borrow::Cow, cell::OnceCell, cell::RefCell, cmp::{self, Ordering, Reverse}, iter::Peekable, mem, num::NonZeroU32, ops::Not, ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive}, path::{Path, PathBuf}, rc::Rc, sync::Arc, time::{Duration, Instant}, }; use sum_tree::TreeMap; use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables}; use text::{BufferId, FromAnchor, OffsetUtf16, Rope}; use theme::{ ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings, observe_buffer_font_size_adjustment, }; use ui::{ ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, }; use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc}; use workspace::{ CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings, item::{ItemHandle, PreviewTabsSettings, SaveOptions}, notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt}, searchable::SearchEvent, }; use crate::{ code_context_menus::CompletionsMenuSource, editor_settings::MultiCursorModifier, hover_links::{find_url, find_url_from_range}, signature_help::{SignatureHelpHiddenBy, SignatureHelpState}, }; pub const FILE_HEADER_HEIGHT: u32 = 2; pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1; pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2; 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; pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000); #[doc(hidden)] pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250); const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100); pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5); pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5); pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1); pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction"; pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict"; pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.)); pub type RenderDiffHunkControlsFn = Arc< dyn Fn( u32, &DiffHunkStatus, Range<Anchor>, bool, Pixels, &Entity<Editor>, &mut Window, &mut App, ) -> AnyElement, >; enum ReportEditorEvent { Saved { auto_saved: bool }, EditorOpened, ZetaTosClicked, Closed, } impl ReportEditorEvent { pub fn event_type(&self) -> &'static str { match self { Self::Saved { .. } => "Editor Saved", Self::EditorOpened => "Editor Opened", Self::ZetaTosClicked => "Edit Prediction Provider ToS Clicked", Self::Closed => "Editor Closed", } } } struct InlineValueCache { enabled: bool, inlays: Vec<InlayId>, refresh_task: Task<Option<()>>, } impl InlineValueCache { fn new(enabled: bool) -> Self { Self { enabled, inlays: Vec::new(), refresh_task: Task::ready(None), } } } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum InlayId { EditPrediction(usize), DebuggerValue(usize), // LSP Hint(usize), Color(usize), } impl InlayId { fn id(&self) -> usize { match self { Self::EditPrediction(id) => *id, Self::DebuggerValue(id) => *id, Self::Hint(id) => *id, Self::Color(id) => *id, } } } pub enum ActiveDebugLine {} pub enum DebugStackFrameLine {} enum DocumentHighlightRead {} enum DocumentHighlightWrite {} enum InputComposition {} pub enum PendingInput {} enum SelectedTextHighlight {} pub enum ConflictsOuter {} pub enum ConflictsOurs {} pub enum ConflictsTheirs {} pub enum ConflictsOursMarker {} pub enum ConflictsTheirsMarker {} #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Navigated { Yes, No, } impl Navigated { pub fn from_bool(yes: bool) -> Navigated { if yes { Navigated::Yes } else { Navigated::No } } } #[derive(Debug, Clone, PartialEq, Eq)] enum DisplayDiffHunk { Folded { display_row: DisplayRow, }, Unfolded { is_created_file: bool, diff_base_byte_range: Range<usize>, display_row_range: Range<DisplayRow>, multi_buffer_range: Range<Anchor>, status: DiffHunkStatus, }, } pub enum HideMouseCursorOrigin { TypingAction, MovementAction, } pub fn init_settings(cx: &mut App) { EditorSettings::register(cx); } pub fn init(cx: &mut App) { init_settings(cx); cx.set_global(GlobalBlameRenderer(Arc::new(()))); workspace::register_project_item::<Editor>(cx); workspace::FollowableViewRegistry::register::<Editor>(cx); workspace::register_serializable_item::<Editor>(cx); cx.observe_new( |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| { workspace.register_action(Editor::new_file); workspace.register_action(Editor::new_file_vertical); workspace.register_action(Editor::new_file_horizontal); workspace.register_action(Editor::cancel_language_server_work); workspace.register_action(Editor::toggle_focus); }, ) .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( Default::default(), app_state, cx, |workspace, window, cx| { Editor::new_file(workspace, &Default::default(), window, 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( Default::default(), app_state, cx, |workspace, window, cx| { cx.activate(true); Editor::new_file(workspace, &Default::default(), window, cx) }, ) .detach(); } }); } pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) { cx.set_global(GlobalBlameRenderer(Arc::new(renderer))); } pub trait DiagnosticRenderer { fn render_group( &self, diagnostic_group: Vec<DiagnosticEntry<Point>>, buffer_id: BufferId, snapshot: EditorSnapshot, editor: WeakEntity<Editor>, cx: &mut App, ) -> Vec<BlockProperties<Anchor>>; fn render_hover( &self, diagnostic_group: Vec<DiagnosticEntry<Point>>, range: Range<Point>, buffer_id: BufferId, cx: &mut App, ) -> Option<Entity<markdown::Markdown>>; fn open_link( &self, editor: &mut Editor, link: SharedString, window: &mut Window, cx: &mut Context<Editor>, ); } pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>); impl GlobalDiagnosticRenderer { fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> { cx.try_global::<Self>().map(|g| g.0.clone()) } } impl gpui::Global for GlobalDiagnosticRenderer {} pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) { cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer))); } pub struct SearchWithinRange; 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, reset: bool, mode: ColumnarMode, goal_column: u32, }, Extend { position: DisplayPoint, click_count: usize, }, Update { position: DisplayPoint, goal_column: u32, scroll_delta: gpui::Point<f32>, }, End, } #[derive(Clone, Debug, PartialEq)] pub enum ColumnarMode { FromMouse, FromSelection, } #[derive(Clone, Debug)] pub enum SelectMode { Character, Word(Range<Anchor>), Line(Range<Anchor>), All, } #[derive(Clone, PartialEq, Eq, Debug)] pub enum EditorMode { SingleLine, AutoHeight { min_lines: usize,