#![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.).//!//! 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;pub mod blink_manager;mod bracket_colorization;mod clangd_ext;pub mod code_context_menus;pub mod display_map;mod document_colors;mod document_symbols;mod editor_settings;mod element;mod folding_ranges;mod git;mod highlight_matching_bracket;mod hover_links;pub mod hover_popover;mod indent_guides;mod inlays;pub mod items;mod jsx_tag_auto_close;mod linked_editing_ranges;mod lsp_ext;mod mouse_context_menu;pub mod movement;mod persistence;mod runnables;mod rust_analyzer_ext;pub mod scroll;mod selections_collection;pub mod semantic_tokens;mod split;pub mod split_editor_view; #[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, HighlightKey, SemanticTokenHighlight,};pub use edit_prediction_types::Direction;pub use editor_settings::{ CompletionDetailAlignment, CurrentLineHighlight, DiffViewStyle, DocumentColorsRenderMode, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,};pub use element::{ CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition, render_breadcrumb_text,};pub use git::blame::BlameRenderer;pub use hover_popover::hover_markdown_style;pub use inlays::Inlay;pub use items::MAX_TAB_TITLE_LEN;pub use linked_editing_ranges::LinkedEdits;pub use lsp::CompletionContext;pub use lsp_ext::lsp_tasks;pub use multi_buffer::{ Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer, MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset, ToPoint,};pub use split::{SplittableEditor, ToggleSplitDiff};pub use split_editor_view::SplitEditorView;pub use text::Bias; use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};use anyhow::{Context as _, Result, anyhow, bail};use blink_manager::BlinkManager;use buffer_diff::DiffHunkStatus;use client::{Collaborator, ParticipantIndex, parse_zed_link};use clock::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 document_colors::LspColorData;use edit_prediction_types::{ EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionDiscardReason, EditPredictionGranularity, SuggestionDisplayType,};use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};use futures::{ FutureExt, future::{self, Shared, join},};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, EntityId, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId, FontStyle, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage, Render, ScrollHandle, SharedString, SharedUri, Size, Stateful, Styled, Subscription, Task, TextRun, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative, size,};use hover_links::{HoverLink, HoveredLinkState, find_file};use hover_popover::{HoverState, hide_hover};use indent_guides::ActiveIndentGuidesState;use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};use itertools::{Either, Itertools};use language::{ AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow, BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape, DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, LocalFile, OffsetRangeExt, OutlineItem, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery, language_settings::{ self, LanguageSettings, 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 markdown::Markdown;use mouse_context_menu::MouseContextMenu;use movement::TextLayoutDetails;use multi_buffer::{ ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,};use parking_lot::Mutex;use persistence::DB;use project::{ BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent, CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId, InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, debugger::{ breakpoint_store::{ Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore, BreakpointStoreEvent, }, session::{Session, SessionEvent}, }, git_store::GitStoreEvent, lsp_store::{ BufferSemanticTokens, CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle, RefreshForServer, }, project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},};use rand::seq::SliceRandom;use regex::Regex;use rpc::{ErrorCode, ErrorExt, proto::PeerId};use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, SharedScrollAnchor};use selections_collection::{MutableSelectionsCollection, SelectionsCollection};use serde::{Deserialize, Serialize};use settings::{ GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore, update_settings_file,};use smallvec::{SmallVec, smallvec};use snippet::Snippet;use std::{ any::{Any, TypeId}, borrow::Cow, cell::{OnceCell, RefCell}, cmp::{self, Ordering, Reverse}, collections::hash_map, iter::{self, Peekable}, mem, num::NonZeroU32, ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive}, path::{Path, PathBuf}, rc::Rc, sync::Arc, time::{Duration, Instant},};use task::TaskVariables;use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _, ToPoint as _};use theme::{ AccentColors, ActiveTheme, GlobalTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings, observe_buffer_font_size_adjustment,};use ui::{ Avatar, ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide, utils::WithRemSize,};use ui_input::ErasedEditor;use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};use workspace::{ CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, NavigationEntry, OpenInTerminal, OpenTerminal, Pane, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings, item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions}, notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt}, searchable::SearchEvent,};use zed_actions::editor::{MoveDown, MoveUp}; use crate::{ code_context_menus::CompletionsMenuSource, editor_settings::MultiCursorModifier, hover_links::{find_url, find_url_from_range}, inlays::{ InlineValueCache, inlay_hints::{LspInlayHintData, inlay_hint_settings}, }, runnables::{ResolvedTasks, RunnableData, RunnableTasks}, scroll::{ScrollOffset, ScrollPixelOffset}, selections_collection::resolve_selections_wrapping_blocks, semantic_tokens::SemanticTokenState, signature_help::{SignatureHelpHiddenBy, SignatureHelpState},}; pub const FILE_HEADER_HEIGHT: u32 = 2;pub const BUFFER_HEADER_PADDING: Rems = rems(0.25);pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;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);pub 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 const LSP_REQUEST_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(50); 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, Closed,} impl ReportEditorEvent { pub fn event_type(&self) -> &'static str { match self { Self::Saved { .. } => "Editor Saved", Self::EditorOpened => "Editor Opened", Self::Closed => "Editor Closed", } }} pub enum ActiveDebugLine {}pub enum DebugStackFrameLine {} pub enum ConflictsOuter {}pub enum ConflictsOurs {}pub enum ConflictsTheirs {}pub enum ConflictsOursMarker {}pub enum ConflictsTheirsMarker {} pub struct HunkAddedColor;pub struct HunkRemovedColor; #[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, word_diffs: Vec<Range<MultiBufferOffset>>, },} pub enum HideMouseCursorOrigin { TypingAction, MovementAction,} pub fn init(cx: &mut App) { cx.set_global(GlobalBlameRenderer(Arc::new(()))); cx.set_global(breadcrumbs::RenderBreadcrumbText(render_breadcrumb_text)); 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_split); 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_and_log_err(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_and_log_err(cx); } }); _ = ui_input::ERASED_EDITOR_FACTORY.set(|window, cx| { Arc::new(ErasedEditorImpl( cx.new(|cx| Editor::single_line(window, cx)), )) as Arc<dyn ErasedEditor> }); _ = multi_buffer::EXCERPT_CONTEXT_LINES.set(multibuffer_context_lines);} 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<DiagnosticEntryRef<'_, Point>>, buffer_id: BufferId, snapshot: EditorSnapshot, editor: WeakEntity<Editor>, language_registry: Option<Arc<LanguageRegistry>>, cx: &mut App, ) -> Vec<BlockProperties<Anchor>>; fn render_hover( &self, diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>, range: Range<Point>, buffer_id: BufferId, language_registry: Option<Arc<LanguageRegistry>>, 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(Copy, Clone, Default, PartialEq, Eq, Debug)]pub enum SizingBehavior { /// The editor will layout itself using `size_full` and will include the vertical /// scroll margin as requested by user settings. #[default] Default, /// The editor will layout itself using `size_full`, but will not have any /// vertical overscroll. ExcludeOverscrollMargin, /// The editor will request a vertical size according to its content and will be /// layouted without a vertical scroll margin. SizeByContent,} #[derive(Clone, PartialEq, Eq, Debug)]pub enum EditorMode { SingleLine, AutoHeight {Lines 1–500 of 29021. 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.). //! //! 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; pub mod blink_manager; mod bracket_colorization; mod clangd_ext; pub mod code_context_menus; pub mod display_map; mod document_colors; mod document_symbols; mod editor_settings; mod element; mod folding_ranges; mod git; mod highlight_matching_bracket; mod hover_links; pub mod hover_popover; mod indent_guides; mod inlays; pub mod items; mod jsx_tag_auto_close; mod linked_editing_ranges; mod lsp_ext; mod mouse_context_menu; pub mod movement; mod persistence; mod runnables; mod rust_analyzer_ext; pub mod scroll; mod selections_collection; pub mod semantic_tokens; mod split; pub mod split_editor_view; #[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, HighlightKey, SemanticTokenHighlight, }; pub use edit_prediction_types::Direction; pub use editor_settings::{ CompletionDetailAlignment, CurrentLineHighlight, DiffViewStyle, DocumentColorsRenderMode, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, }; pub use element::{ CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition, render_breadcrumb_text, }; pub use git::blame::BlameRenderer; pub use hover_popover::hover_markdown_style; pub use inlays::Inlay; pub use items::MAX_TAB_TITLE_LEN; pub use linked_editing_ranges::LinkedEdits; pub use lsp::CompletionContext; pub use lsp_ext::lsp_tasks; pub use multi_buffer::{ Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer, MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset, ToPoint, }; pub use split::{SplittableEditor, ToggleSplitDiff}; pub use split_editor_view::SplitEditorView; pub use text::Bias; use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus}; use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError}; use anyhow::{Context as _, Result, anyhow, bail}; use blink_manager::BlinkManager; use buffer_diff::DiffHunkStatus; use client::{Collaborator, ParticipantIndex, parse_zed_link}; use clock::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 document_colors::LspColorData; use edit_prediction_types::{ EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionDiscardReason, EditPredictionGranularity, SuggestionDisplayType, }; use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings}; use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line}; use futures::{ FutureExt, future::{self, Shared, join}, }; 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, EntityId, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId, FontStyle, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage, Render, ScrollHandle, SharedString, SharedUri, Size, Stateful, Styled, Subscription, Task, TextRun, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative, size, }; use hover_links::{HoverLink, HoveredLinkState, find_file}; use hover_popover::{HoverState, hide_hover}; use indent_guides::ActiveIndentGuidesState; use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason}; use itertools::{Either, Itertools}; use language::{ AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow, BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape, DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, LocalFile, OffsetRangeExt, OutlineItem, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery, language_settings::{ self, LanguageSettings, 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 markdown::Markdown; use mouse_context_menu::MouseContextMenu; use movement::TextLayoutDetails; use multi_buffer::{ ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow, }; use parking_lot::Mutex; use persistence::DB; use project::{ BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent, CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId, InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, debugger::{ breakpoint_store::{ Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore, BreakpointStoreEvent, }, session::{Session, SessionEvent}, }, git_store::GitStoreEvent, lsp_store::{ BufferSemanticTokens, CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle, RefreshForServer, }, project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings}, }; use rand::seq::SliceRandom; use regex::Regex; use rpc::{ErrorCode, ErrorExt, proto::PeerId}; use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, SharedScrollAnchor}; use selections_collection::{MutableSelectionsCollection, SelectionsCollection}; use serde::{Deserialize, Serialize}; use settings::{ GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore, update_settings_file, }; use smallvec::{SmallVec, smallvec}; use snippet::Snippet; use std::{ any::{Any, TypeId}, borrow::Cow, cell::{OnceCell, RefCell}, cmp::{self, Ordering, Reverse}, collections::hash_map, iter::{self, Peekable}, mem, num::NonZeroU32, ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive}, path::{Path, PathBuf}, rc::Rc, sync::Arc, time::{Duration, Instant}, }; use task::TaskVariables; use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _, ToPoint as _}; use theme::{ AccentColors, ActiveTheme, GlobalTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings, observe_buffer_font_size_adjustment, }; use ui::{ Avatar, ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide, utils::WithRemSize, }; use ui_input::ErasedEditor; use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc}; use workspace::{ CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, NavigationEntry, OpenInTerminal, OpenTerminal, Pane, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings, item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions}, notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt}, searchable::SearchEvent, }; use zed_actions::editor::{MoveDown, MoveUp}; use crate::{ code_context_menus::CompletionsMenuSource, editor_settings::MultiCursorModifier, hover_links::{find_url, find_url_from_range}, inlays::{ InlineValueCache, inlay_hints::{LspInlayHintData, inlay_hint_settings}, }, runnables::{ResolvedTasks, RunnableData, RunnableTasks}, scroll::{ScrollOffset, ScrollPixelOffset}, selections_collection::resolve_selections_wrapping_blocks, semantic_tokens::SemanticTokenState, signature_help::{SignatureHelpHiddenBy, SignatureHelpState}, }; pub const FILE_HEADER_HEIGHT: u32 = 2; pub const BUFFER_HEADER_PADDING: Rems = rems(0.25); pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1; 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); pub 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 const LSP_REQUEST_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(50); 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, Closed, } impl ReportEditorEvent { pub fn event_type(&self) -> &'static str { match self { Self::Saved { .. } => "Editor Saved", Self::EditorOpened => "Editor Opened", Self::Closed => "Editor Closed", } } } pub enum ActiveDebugLine {} pub enum DebugStackFrameLine {} pub enum ConflictsOuter {} pub enum ConflictsOurs {} pub enum ConflictsTheirs {} pub enum ConflictsOursMarker {} pub enum ConflictsTheirsMarker {} pub struct HunkAddedColor; pub struct HunkRemovedColor; #[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, word_diffs: Vec<Range<MultiBufferOffset>>, }, } pub enum HideMouseCursorOrigin { TypingAction, MovementAction, } pub fn init(cx: &mut App) { cx.set_global(GlobalBlameRenderer(Arc::new(()))); cx.set_global(breadcrumbs::RenderBreadcrumbText(render_breadcrumb_text)); 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_split); 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_and_log_err(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_and_log_err(cx); } }); _ = ui_input::ERASED_EDITOR_FACTORY.set(|window, cx| { Arc::new(ErasedEditorImpl( cx.new(|cx| Editor::single_line(window, cx)), )) as Arc<dyn ErasedEditor> }); _ = multi_buffer::EXCERPT_CONTEXT_LINES.set(multibuffer_context_lines); } 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<DiagnosticEntryRef<'_, Point>>, buffer_id: BufferId, snapshot: EditorSnapshot, editor: WeakEntity<Editor>, language_registry: Option<Arc<LanguageRegistry>>, cx: &mut App, ) -> Vec<BlockProperties<Anchor>>; fn render_hover( &self, diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>, range: Range<Point>, buffer_id: BufferId, language_registry: Option<Arc<LanguageRegistry>>, 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(Copy, Clone, Default, PartialEq, Eq, Debug)] pub enum SizingBehavior { /// The editor will layout itself using `size_full` and will include the vertical /// scroll margin as requested by user settings. #[default] Default, /// The editor will layout itself using `size_full`, but will not have any /// vertical overscroll. ExcludeOverscrollMargin, /// The editor will request a vertical size according to its content and will be /// layouted without a vertical scroll margin. SizeByContent, } #[derive(Clone, PartialEq, Eq, Debug)] pub enum EditorMode { SingleLine, AutoHeight {