editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  113    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  114    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  115    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, ProjectPath,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    git_store::{GitStoreEvent, RepositoryEvent},
  137    project_settings::DiagnosticSeverity,
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    hover_links::{find_url, find_url_from_range},
  220};
  221use crate::{
  222    editor_settings::MultiCursorModifier,
  223    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  224};
  225
  226pub const FILE_HEADER_HEIGHT: u32 = 2;
  227pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  228pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241
  242pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  243pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  244pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  245
  246pub type RenderDiffHunkControlsFn = Arc<
  247    dyn Fn(
  248        u32,
  249        &DiffHunkStatus,
  250        Range<Anchor>,
  251        bool,
  252        Pixels,
  253        &Entity<Editor>,
  254        &mut Window,
  255        &mut App,
  256    ) -> AnyElement,
  257>;
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    DebuggerValue(usize),
  279    // LSP
  280    Hint(usize),
  281    Color(usize),
  282}
  283
  284impl InlayId {
  285    fn id(&self) -> usize {
  286        match self {
  287            Self::InlineCompletion(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289            Self::Hint(id) => *id,
  290            Self::Color(id) => *id,
  291        }
  292    }
  293}
  294
  295pub enum ActiveDebugLine {}
  296pub enum DebugStackFrameLine {}
  297enum DocumentHighlightRead {}
  298enum DocumentHighlightWrite {}
  299enum InputComposition {}
  300pub enum PendingInput {}
  301enum SelectedTextHighlight {}
  302
  303pub enum ConflictsOuter {}
  304pub enum ConflictsOurs {}
  305pub enum ConflictsTheirs {}
  306pub enum ConflictsOursMarker {}
  307pub enum ConflictsTheirsMarker {}
  308
  309#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  310pub enum Navigated {
  311    Yes,
  312    No,
  313}
  314
  315impl Navigated {
  316    pub fn from_bool(yes: bool) -> Navigated {
  317        if yes { Navigated::Yes } else { Navigated::No }
  318    }
  319}
  320
  321#[derive(Debug, Clone, PartialEq, Eq)]
  322enum DisplayDiffHunk {
  323    Folded {
  324        display_row: DisplayRow,
  325    },
  326    Unfolded {
  327        is_created_file: bool,
  328        diff_base_byte_range: Range<usize>,
  329        display_row_range: Range<DisplayRow>,
  330        multi_buffer_range: Range<Anchor>,
  331        status: DiffHunkStatus,
  332    },
  333}
  334
  335pub enum HideMouseCursorOrigin {
  336    TypingAction,
  337    MovementAction,
  338}
  339
  340pub fn init_settings(cx: &mut App) {
  341    EditorSettings::register(cx);
  342}
  343
  344pub fn init(cx: &mut App) {
  345    init_settings(cx);
  346
  347    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  348
  349    workspace::register_project_item::<Editor>(cx);
  350    workspace::FollowableViewRegistry::register::<Editor>(cx);
  351    workspace::register_serializable_item::<Editor>(cx);
  352
  353    cx.observe_new(
  354        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  355            workspace.register_action(Editor::new_file);
  356            workspace.register_action(Editor::new_file_vertical);
  357            workspace.register_action(Editor::new_file_horizontal);
  358            workspace.register_action(Editor::cancel_language_server_work);
  359        },
  360    )
  361    .detach();
  362
  363    cx.on_action(move |_: &workspace::NewFile, cx| {
  364        let app_state = workspace::AppState::global(cx);
  365        if let Some(app_state) = app_state.upgrade() {
  366            workspace::open_new(
  367                Default::default(),
  368                app_state,
  369                cx,
  370                |workspace, window, cx| {
  371                    Editor::new_file(workspace, &Default::default(), window, cx)
  372                },
  373            )
  374            .detach();
  375        }
  376    });
  377    cx.on_action(move |_: &workspace::NewWindow, cx| {
  378        let app_state = workspace::AppState::global(cx);
  379        if let Some(app_state) = app_state.upgrade() {
  380            workspace::open_new(
  381                Default::default(),
  382                app_state,
  383                cx,
  384                |workspace, window, cx| {
  385                    cx.activate(true);
  386                    Editor::new_file(workspace, &Default::default(), window, cx)
  387                },
  388            )
  389            .detach();
  390        }
  391    });
  392}
  393
  394pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  395    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  396}
  397
  398pub trait DiagnosticRenderer {
  399    fn render_group(
  400        &self,
  401        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  402        buffer_id: BufferId,
  403        snapshot: EditorSnapshot,
  404        editor: WeakEntity<Editor>,
  405        cx: &mut App,
  406    ) -> Vec<BlockProperties<Anchor>>;
  407
  408    fn render_hover(
  409        &self,
  410        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  411        range: Range<Point>,
  412        buffer_id: BufferId,
  413        cx: &mut App,
  414    ) -> Option<Entity<markdown::Markdown>>;
  415
  416    fn open_link(
  417        &self,
  418        editor: &mut Editor,
  419        link: SharedString,
  420        window: &mut Window,
  421        cx: &mut Context<Editor>,
  422    );
  423}
  424
  425pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  426
  427impl GlobalDiagnosticRenderer {
  428    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  429        cx.try_global::<Self>().map(|g| g.0.clone())
  430    }
  431}
  432
  433impl gpui::Global for GlobalDiagnosticRenderer {}
  434pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  435    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  436}
  437
  438pub struct SearchWithinRange;
  439
  440trait InvalidationRegion {
  441    fn ranges(&self) -> &[Range<Anchor>];
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum SelectPhase {
  446    Begin {
  447        position: DisplayPoint,
  448        add: bool,
  449        click_count: usize,
  450    },
  451    BeginColumnar {
  452        position: DisplayPoint,
  453        reset: bool,
  454        mode: ColumnarMode,
  455        goal_column: u32,
  456    },
  457    Extend {
  458        position: DisplayPoint,
  459        click_count: usize,
  460    },
  461    Update {
  462        position: DisplayPoint,
  463        goal_column: u32,
  464        scroll_delta: gpui::Point<f32>,
  465    },
  466    End,
  467}
  468
  469#[derive(Clone, Debug, PartialEq)]
  470pub enum ColumnarMode {
  471    FromMouse,
  472    FromSelection,
  473}
  474
  475#[derive(Clone, Debug)]
  476pub enum SelectMode {
  477    Character,
  478    Word(Range<Anchor>),
  479    Line(Range<Anchor>),
  480    All,
  481}
  482
  483#[derive(Clone, PartialEq, Eq, Debug)]
  484pub enum EditorMode {
  485    SingleLine,
  486    AutoHeight {
  487        min_lines: usize,
  488        max_lines: Option<usize>,
  489    },
  490    Full {
  491        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  492        scale_ui_elements_with_buffer_font_size: bool,
  493        /// When set to `true`, the editor will render a background for the active line.
  494        show_active_line_background: bool,
  495        /// When set to `true`, the editor's height will be determined by its content.
  496        sized_by_content: bool,
  497    },
  498    Minimap {
  499        parent: WeakEntity<Editor>,
  500    },
  501}
  502
  503impl EditorMode {
  504    pub fn full() -> Self {
  505        Self::Full {
  506            scale_ui_elements_with_buffer_font_size: true,
  507            show_active_line_background: true,
  508            sized_by_content: false,
  509        }
  510    }
  511
  512    #[inline]
  513    pub fn is_full(&self) -> bool {
  514        matches!(self, Self::Full { .. })
  515    }
  516
  517    #[inline]
  518    pub fn is_single_line(&self) -> bool {
  519        matches!(self, Self::SingleLine { .. })
  520    }
  521
  522    #[inline]
  523    fn is_minimap(&self) -> bool {
  524        matches!(self, Self::Minimap { .. })
  525    }
  526}
  527
  528#[derive(Copy, Clone, Debug)]
  529pub enum SoftWrap {
  530    /// Prefer not to wrap at all.
  531    ///
  532    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  533    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  534    GitDiff,
  535    /// Prefer a single line generally, unless an overly long line is encountered.
  536    None,
  537    /// Soft wrap lines that exceed the editor width.
  538    EditorWidth,
  539    /// Soft wrap lines at the preferred line length.
  540    Column(u32),
  541    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  542    Bounded(u32),
  543}
  544
  545#[derive(Clone)]
  546pub struct EditorStyle {
  547    pub background: Hsla,
  548    pub border: Hsla,
  549    pub local_player: PlayerColor,
  550    pub text: TextStyle,
  551    pub scrollbar_width: Pixels,
  552    pub syntax: Arc<SyntaxTheme>,
  553    pub status: StatusColors,
  554    pub inlay_hints_style: HighlightStyle,
  555    pub inline_completion_styles: InlineCompletionStyles,
  556    pub unnecessary_code_fade: f32,
  557    pub show_underlines: bool,
  558}
  559
  560impl Default for EditorStyle {
  561    fn default() -> Self {
  562        Self {
  563            background: Hsla::default(),
  564            border: Hsla::default(),
  565            local_player: PlayerColor::default(),
  566            text: TextStyle::default(),
  567            scrollbar_width: Pixels::default(),
  568            syntax: Default::default(),
  569            // HACK: Status colors don't have a real default.
  570            // We should look into removing the status colors from the editor
  571            // style and retrieve them directly from the theme.
  572            status: StatusColors::dark(),
  573            inlay_hints_style: HighlightStyle::default(),
  574            inline_completion_styles: InlineCompletionStyles {
  575                insertion: HighlightStyle::default(),
  576                whitespace: HighlightStyle::default(),
  577            },
  578            unnecessary_code_fade: Default::default(),
  579            show_underlines: true,
  580        }
  581    }
  582}
  583
  584pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  585    let show_background = language_settings::language_settings(None, None, cx)
  586        .inlay_hints
  587        .show_background;
  588
  589    HighlightStyle {
  590        color: Some(cx.theme().status().hint),
  591        background_color: show_background.then(|| cx.theme().status().hint_background),
  592        ..HighlightStyle::default()
  593    }
  594}
  595
  596pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  597    InlineCompletionStyles {
  598        insertion: HighlightStyle {
  599            color: Some(cx.theme().status().predictive),
  600            ..HighlightStyle::default()
  601        },
  602        whitespace: HighlightStyle {
  603            background_color: Some(cx.theme().status().created_background),
  604            ..HighlightStyle::default()
  605        },
  606    }
  607}
  608
  609type CompletionId = usize;
  610
  611pub(crate) enum EditDisplayMode {
  612    TabAccept,
  613    DiffPopover,
  614    Inline,
  615}
  616
  617enum InlineCompletion {
  618    Edit {
  619        edits: Vec<(Range<Anchor>, String)>,
  620        edit_preview: Option<EditPreview>,
  621        display_mode: EditDisplayMode,
  622        snapshot: BufferSnapshot,
  623    },
  624    Move {
  625        target: Anchor,
  626        snapshot: BufferSnapshot,
  627    },
  628}
  629
  630struct InlineCompletionState {
  631    inlay_ids: Vec<InlayId>,
  632    completion: InlineCompletion,
  633    completion_id: Option<SharedString>,
  634    invalidation_range: Range<Anchor>,
  635}
  636
  637enum EditPredictionSettings {
  638    Disabled,
  639    Enabled {
  640        show_in_menu: bool,
  641        preview_requires_modifier: bool,
  642    },
  643}
  644
  645enum InlineCompletionHighlight {}
  646
  647#[derive(Debug, Clone)]
  648struct InlineDiagnostic {
  649    message: SharedString,
  650    group_id: usize,
  651    is_primary: bool,
  652    start: Point,
  653    severity: lsp::DiagnosticSeverity,
  654}
  655
  656pub enum MenuInlineCompletionsPolicy {
  657    Never,
  658    ByProvider,
  659}
  660
  661pub enum EditPredictionPreview {
  662    /// Modifier is not pressed
  663    Inactive { released_too_fast: bool },
  664    /// Modifier pressed
  665    Active {
  666        since: Instant,
  667        previous_scroll_position: Option<ScrollAnchor>,
  668    },
  669}
  670
  671impl EditPredictionPreview {
  672    pub fn released_too_fast(&self) -> bool {
  673        match self {
  674            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  675            EditPredictionPreview::Active { .. } => false,
  676        }
  677    }
  678
  679    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  680        if let EditPredictionPreview::Active {
  681            previous_scroll_position,
  682            ..
  683        } = self
  684        {
  685            *previous_scroll_position = scroll_position;
  686        }
  687    }
  688}
  689
  690pub struct ContextMenuOptions {
  691    pub min_entries_visible: usize,
  692    pub max_entries_visible: usize,
  693    pub placement: Option<ContextMenuPlacement>,
  694}
  695
  696#[derive(Debug, Clone, PartialEq, Eq)]
  697pub enum ContextMenuPlacement {
  698    Above,
  699    Below,
  700}
  701
  702#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  703struct EditorActionId(usize);
  704
  705impl EditorActionId {
  706    pub fn post_inc(&mut self) -> Self {
  707        let answer = self.0;
  708
  709        *self = Self(answer + 1);
  710
  711        Self(answer)
  712    }
  713}
  714
  715// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  716// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  717
  718type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  719type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  720
  721#[derive(Default)]
  722struct ScrollbarMarkerState {
  723    scrollbar_size: Size<Pixels>,
  724    dirty: bool,
  725    markers: Arc<[PaintQuad]>,
  726    pending_refresh: Option<Task<Result<()>>>,
  727}
  728
  729impl ScrollbarMarkerState {
  730    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  731        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  732    }
  733}
  734
  735#[derive(Clone, Copy, PartialEq, Eq)]
  736pub enum MinimapVisibility {
  737    Disabled,
  738    Enabled {
  739        /// The configuration currently present in the users settings.
  740        setting_configuration: bool,
  741        /// Whether to override the currently set visibility from the users setting.
  742        toggle_override: bool,
  743    },
  744}
  745
  746impl MinimapVisibility {
  747    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  748        if mode.is_full() {
  749            Self::Enabled {
  750                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  751                toggle_override: false,
  752            }
  753        } else {
  754            Self::Disabled
  755        }
  756    }
  757
  758    fn hidden(&self) -> Self {
  759        match *self {
  760            Self::Enabled {
  761                setting_configuration,
  762                ..
  763            } => Self::Enabled {
  764                setting_configuration,
  765                toggle_override: setting_configuration,
  766            },
  767            Self::Disabled => Self::Disabled,
  768        }
  769    }
  770
  771    fn disabled(&self) -> bool {
  772        match *self {
  773            Self::Disabled => true,
  774            _ => false,
  775        }
  776    }
  777
  778    fn settings_visibility(&self) -> bool {
  779        match *self {
  780            Self::Enabled {
  781                setting_configuration,
  782                ..
  783            } => setting_configuration,
  784            _ => false,
  785        }
  786    }
  787
  788    fn visible(&self) -> bool {
  789        match *self {
  790            Self::Enabled {
  791                setting_configuration,
  792                toggle_override,
  793            } => setting_configuration ^ toggle_override,
  794            _ => false,
  795        }
  796    }
  797
  798    fn toggle_visibility(&self) -> Self {
  799        match *self {
  800            Self::Enabled {
  801                toggle_override,
  802                setting_configuration,
  803            } => Self::Enabled {
  804                setting_configuration,
  805                toggle_override: !toggle_override,
  806            },
  807            Self::Disabled => Self::Disabled,
  808        }
  809    }
  810}
  811
  812#[derive(Clone, Debug)]
  813struct RunnableTasks {
  814    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  815    offset: multi_buffer::Anchor,
  816    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  817    column: u32,
  818    // Values of all named captures, including those starting with '_'
  819    extra_variables: HashMap<String, String>,
  820    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  821    context_range: Range<BufferOffset>,
  822}
  823
  824impl RunnableTasks {
  825    fn resolve<'a>(
  826        &'a self,
  827        cx: &'a task::TaskContext,
  828    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  829        self.templates.iter().filter_map(|(kind, template)| {
  830            template
  831                .resolve_task(&kind.to_id_base(), cx)
  832                .map(|task| (kind.clone(), task))
  833        })
  834    }
  835}
  836
  837#[derive(Clone)]
  838pub struct ResolvedTasks {
  839    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  840    position: Anchor,
  841}
  842
  843#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  844struct BufferOffset(usize);
  845
  846// Addons allow storing per-editor state in other crates (e.g. Vim)
  847pub trait Addon: 'static {
  848    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  849
  850    fn render_buffer_header_controls(
  851        &self,
  852        _: &ExcerptInfo,
  853        _: &Window,
  854        _: &App,
  855    ) -> Option<AnyElement> {
  856        None
  857    }
  858
  859    fn to_any(&self) -> &dyn std::any::Any;
  860
  861    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  862        None
  863    }
  864}
  865
  866struct ChangeLocation {
  867    current: Option<Vec<Anchor>>,
  868    original: Vec<Anchor>,
  869}
  870impl ChangeLocation {
  871    fn locations(&self) -> &[Anchor] {
  872        self.current.as_ref().unwrap_or(&self.original)
  873    }
  874}
  875
  876/// A set of caret positions, registered when the editor was edited.
  877pub struct ChangeList {
  878    changes: Vec<ChangeLocation>,
  879    /// Currently "selected" change.
  880    position: Option<usize>,
  881}
  882
  883impl ChangeList {
  884    pub fn new() -> Self {
  885        Self {
  886            changes: Vec::new(),
  887            position: None,
  888        }
  889    }
  890
  891    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  892    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  893    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  894        if self.changes.is_empty() {
  895            return None;
  896        }
  897
  898        let prev = self.position.unwrap_or(self.changes.len());
  899        let next = if direction == Direction::Prev {
  900            prev.saturating_sub(count)
  901        } else {
  902            (prev + count).min(self.changes.len() - 1)
  903        };
  904        self.position = Some(next);
  905        self.changes.get(next).map(|change| change.locations())
  906    }
  907
  908    /// Adds a new change to the list, resetting the change list position.
  909    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  910        self.position.take();
  911        if let Some(last) = self.changes.last_mut()
  912            && group
  913        {
  914            last.current = Some(new_positions)
  915        } else {
  916            self.changes.push(ChangeLocation {
  917                original: new_positions,
  918                current: None,
  919            });
  920        }
  921    }
  922
  923    pub fn last(&self) -> Option<&[Anchor]> {
  924        self.changes.last().map(|change| change.locations())
  925    }
  926
  927    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  928        self.changes.last().map(|change| change.original.as_slice())
  929    }
  930
  931    pub fn invert_last_group(&mut self) {
  932        if let Some(last) = self.changes.last_mut() {
  933            if let Some(current) = last.current.as_mut() {
  934                mem::swap(&mut last.original, current);
  935            }
  936        }
  937    }
  938}
  939
  940#[derive(Clone)]
  941struct InlineBlamePopoverState {
  942    scroll_handle: ScrollHandle,
  943    commit_message: Option<ParsedCommitMessage>,
  944    markdown: Entity<Markdown>,
  945}
  946
  947struct InlineBlamePopover {
  948    position: gpui::Point<Pixels>,
  949    hide_task: Option<Task<()>>,
  950    popover_bounds: Option<Bounds<Pixels>>,
  951    popover_state: InlineBlamePopoverState,
  952}
  953
  954enum SelectionDragState {
  955    /// State when no drag related activity is detected.
  956    None,
  957    /// State when the mouse is down on a selection that is about to be dragged.
  958    ReadyToDrag {
  959        selection: Selection<Anchor>,
  960        click_position: gpui::Point<Pixels>,
  961        mouse_down_time: Instant,
  962    },
  963    /// State when the mouse is dragging the selection in the editor.
  964    Dragging {
  965        selection: Selection<Anchor>,
  966        drop_cursor: Selection<Anchor>,
  967        hide_drop_cursor: bool,
  968    },
  969}
  970
  971enum ColumnarSelectionState {
  972    FromMouse {
  973        selection_tail: Anchor,
  974        display_point: Option<DisplayPoint>,
  975    },
  976    FromSelection {
  977        selection_tail: Anchor,
  978    },
  979}
  980
  981/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  982/// a breakpoint on them.
  983#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  984struct PhantomBreakpointIndicator {
  985    display_row: DisplayRow,
  986    /// There's a small debounce between hovering over the line and showing the indicator.
  987    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  988    is_active: bool,
  989    collides_with_existing_breakpoint: bool,
  990}
  991
  992/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  993///
  994/// See the [module level documentation](self) for more information.
  995pub struct Editor {
  996    focus_handle: FocusHandle,
  997    last_focused_descendant: Option<WeakFocusHandle>,
  998    /// The text buffer being edited
  999    buffer: Entity<MultiBuffer>,
 1000    /// Map of how text in the buffer should be displayed.
 1001    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1002    pub display_map: Entity<DisplayMap>,
 1003    pub selections: SelectionsCollection,
 1004    pub scroll_manager: ScrollManager,
 1005    /// When inline assist editors are linked, they all render cursors because
 1006    /// typing enters text into each of them, even the ones that aren't focused.
 1007    pub(crate) show_cursor_when_unfocused: bool,
 1008    columnar_selection_state: Option<ColumnarSelectionState>,
 1009    add_selections_state: Option<AddSelectionsState>,
 1010    select_next_state: Option<SelectNextState>,
 1011    select_prev_state: Option<SelectNextState>,
 1012    selection_history: SelectionHistory,
 1013    defer_selection_effects: bool,
 1014    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1015    autoclose_regions: Vec<AutocloseRegion>,
 1016    snippet_stack: InvalidationStack<SnippetState>,
 1017    select_syntax_node_history: SelectSyntaxNodeHistory,
 1018    ime_transaction: Option<TransactionId>,
 1019    pub diagnostics_max_severity: DiagnosticSeverity,
 1020    active_diagnostics: ActiveDiagnostic,
 1021    show_inline_diagnostics: bool,
 1022    inline_diagnostics_update: Task<()>,
 1023    inline_diagnostics_enabled: bool,
 1024    diagnostics_enabled: bool,
 1025    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1026    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1027    hard_wrap: Option<usize>,
 1028
 1029    // TODO: make this a access method
 1030    pub project: Option<Entity<Project>>,
 1031    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1032    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1033    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1034    blink_manager: Entity<BlinkManager>,
 1035    show_cursor_names: bool,
 1036    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1037    pub show_local_selections: bool,
 1038    mode: EditorMode,
 1039    show_breadcrumbs: bool,
 1040    show_gutter: bool,
 1041    show_scrollbars: ScrollbarAxes,
 1042    minimap_visibility: MinimapVisibility,
 1043    offset_content: bool,
 1044    disable_expand_excerpt_buttons: bool,
 1045    show_line_numbers: Option<bool>,
 1046    use_relative_line_numbers: Option<bool>,
 1047    show_git_diff_gutter: Option<bool>,
 1048    show_code_actions: Option<bool>,
 1049    show_runnables: Option<bool>,
 1050    show_breakpoints: Option<bool>,
 1051    show_wrap_guides: Option<bool>,
 1052    show_indent_guides: Option<bool>,
 1053    placeholder_text: Option<Arc<str>>,
 1054    highlight_order: usize,
 1055    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1056    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1057    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1058    scrollbar_marker_state: ScrollbarMarkerState,
 1059    active_indent_guides_state: ActiveIndentGuidesState,
 1060    nav_history: Option<ItemNavHistory>,
 1061    context_menu: RefCell<Option<CodeContextMenu>>,
 1062    context_menu_options: Option<ContextMenuOptions>,
 1063    mouse_context_menu: Option<MouseContextMenu>,
 1064    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1065    inline_blame_popover: Option<InlineBlamePopover>,
 1066    inline_blame_popover_show_task: Option<Task<()>>,
 1067    signature_help_state: SignatureHelpState,
 1068    auto_signature_help: Option<bool>,
 1069    find_all_references_task_sources: Vec<Anchor>,
 1070    next_completion_id: CompletionId,
 1071    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1072    code_actions_task: Option<Task<Result<()>>>,
 1073    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1074    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1075    document_highlights_task: Option<Task<()>>,
 1076    linked_editing_range_task: Option<Task<Option<()>>>,
 1077    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1078    pending_rename: Option<RenameState>,
 1079    searchable: bool,
 1080    cursor_shape: CursorShape,
 1081    current_line_highlight: Option<CurrentLineHighlight>,
 1082    collapse_matches: bool,
 1083    autoindent_mode: Option<AutoindentMode>,
 1084    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1085    input_enabled: bool,
 1086    use_modal_editing: bool,
 1087    read_only: bool,
 1088    leader_id: Option<CollaboratorId>,
 1089    remote_id: Option<ViewId>,
 1090    pub hover_state: HoverState,
 1091    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1092    gutter_hovered: bool,
 1093    hovered_link_state: Option<HoveredLinkState>,
 1094    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1095    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1096    active_inline_completion: Option<InlineCompletionState>,
 1097    /// Used to prevent flickering as the user types while the menu is open
 1098    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1099    edit_prediction_settings: EditPredictionSettings,
 1100    inline_completions_hidden_for_vim_mode: bool,
 1101    show_inline_completions_override: Option<bool>,
 1102    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1103    edit_prediction_preview: EditPredictionPreview,
 1104    edit_prediction_indent_conflict: bool,
 1105    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1106    inlay_hint_cache: InlayHintCache,
 1107    next_inlay_id: usize,
 1108    _subscriptions: Vec<Subscription>,
 1109    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1110    gutter_dimensions: GutterDimensions,
 1111    style: Option<EditorStyle>,
 1112    text_style_refinement: Option<TextStyleRefinement>,
 1113    next_editor_action_id: EditorActionId,
 1114    editor_actions: Rc<
 1115        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1116    >,
 1117    use_autoclose: bool,
 1118    use_auto_surround: bool,
 1119    auto_replace_emoji_shortcode: bool,
 1120    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1121    show_git_blame_gutter: bool,
 1122    show_git_blame_inline: bool,
 1123    show_git_blame_inline_delay_task: Option<Task<()>>,
 1124    git_blame_inline_enabled: bool,
 1125    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1126    serialize_dirty_buffers: bool,
 1127    show_selection_menu: Option<bool>,
 1128    blame: Option<Entity<GitBlame>>,
 1129    blame_subscription: Option<Subscription>,
 1130    custom_context_menu: Option<
 1131        Box<
 1132            dyn 'static
 1133                + Fn(
 1134                    &mut Self,
 1135                    DisplayPoint,
 1136                    &mut Window,
 1137                    &mut Context<Self>,
 1138                ) -> Option<Entity<ui::ContextMenu>>,
 1139        >,
 1140    >,
 1141    last_bounds: Option<Bounds<Pixels>>,
 1142    last_position_map: Option<Rc<PositionMap>>,
 1143    expect_bounds_change: Option<Bounds<Pixels>>,
 1144    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1145    tasks_update_task: Option<Task<()>>,
 1146    breakpoint_store: Option<Entity<BreakpointStore>>,
 1147    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1148    hovered_diff_hunk_row: Option<DisplayRow>,
 1149    pull_diagnostics_task: Task<()>,
 1150    in_project_search: bool,
 1151    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1152    breadcrumb_header: Option<String>,
 1153    focused_block: Option<FocusedBlock>,
 1154    next_scroll_position: NextScrollCursorCenterTopBottom,
 1155    addons: HashMap<TypeId, Box<dyn Addon>>,
 1156    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1157    load_diff_task: Option<Shared<Task<()>>>,
 1158    /// Whether we are temporarily displaying a diff other than git's
 1159    temporary_diff_override: bool,
 1160    selection_mark_mode: bool,
 1161    toggle_fold_multiple_buffers: Task<()>,
 1162    _scroll_cursor_center_top_bottom_task: Task<()>,
 1163    serialize_selections: Task<()>,
 1164    serialize_folds: Task<()>,
 1165    mouse_cursor_hidden: bool,
 1166    minimap: Option<Entity<Self>>,
 1167    hide_mouse_mode: HideMouseMode,
 1168    pub change_list: ChangeList,
 1169    inline_value_cache: InlineValueCache,
 1170    selection_drag_state: SelectionDragState,
 1171    next_color_inlay_id: usize,
 1172    colors: Option<LspColorData>,
 1173    folding_newlines: Task<()>,
 1174}
 1175
 1176#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1177enum NextScrollCursorCenterTopBottom {
 1178    #[default]
 1179    Center,
 1180    Top,
 1181    Bottom,
 1182}
 1183
 1184impl NextScrollCursorCenterTopBottom {
 1185    fn next(&self) -> Self {
 1186        match self {
 1187            Self::Center => Self::Top,
 1188            Self::Top => Self::Bottom,
 1189            Self::Bottom => Self::Center,
 1190        }
 1191    }
 1192}
 1193
 1194#[derive(Clone)]
 1195pub struct EditorSnapshot {
 1196    pub mode: EditorMode,
 1197    show_gutter: bool,
 1198    show_line_numbers: Option<bool>,
 1199    show_git_diff_gutter: Option<bool>,
 1200    show_code_actions: Option<bool>,
 1201    show_runnables: Option<bool>,
 1202    show_breakpoints: Option<bool>,
 1203    git_blame_gutter_max_author_length: Option<usize>,
 1204    pub display_snapshot: DisplaySnapshot,
 1205    pub placeholder_text: Option<Arc<str>>,
 1206    is_focused: bool,
 1207    scroll_anchor: ScrollAnchor,
 1208    ongoing_scroll: OngoingScroll,
 1209    current_line_highlight: CurrentLineHighlight,
 1210    gutter_hovered: bool,
 1211}
 1212
 1213#[derive(Default, Debug, Clone, Copy)]
 1214pub struct GutterDimensions {
 1215    pub left_padding: Pixels,
 1216    pub right_padding: Pixels,
 1217    pub width: Pixels,
 1218    pub margin: Pixels,
 1219    pub git_blame_entries_width: Option<Pixels>,
 1220}
 1221
 1222impl GutterDimensions {
 1223    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1224        Self {
 1225            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1226            ..Default::default()
 1227        }
 1228    }
 1229
 1230    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1231        -cx.text_system().descent(font_id, font_size)
 1232    }
 1233    /// The full width of the space taken up by the gutter.
 1234    pub fn full_width(&self) -> Pixels {
 1235        self.margin + self.width
 1236    }
 1237
 1238    /// The width of the space reserved for the fold indicators,
 1239    /// use alongside 'justify_end' and `gutter_width` to
 1240    /// right align content with the line numbers
 1241    pub fn fold_area_width(&self) -> Pixels {
 1242        self.margin + self.right_padding
 1243    }
 1244}
 1245
 1246struct CharacterDimensions {
 1247    em_width: Pixels,
 1248    em_advance: Pixels,
 1249    line_height: Pixels,
 1250}
 1251
 1252#[derive(Debug)]
 1253pub struct RemoteSelection {
 1254    pub replica_id: ReplicaId,
 1255    pub selection: Selection<Anchor>,
 1256    pub cursor_shape: CursorShape,
 1257    pub collaborator_id: CollaboratorId,
 1258    pub line_mode: bool,
 1259    pub user_name: Option<SharedString>,
 1260    pub color: PlayerColor,
 1261}
 1262
 1263#[derive(Clone, Debug)]
 1264struct SelectionHistoryEntry {
 1265    selections: Arc<[Selection<Anchor>]>,
 1266    select_next_state: Option<SelectNextState>,
 1267    select_prev_state: Option<SelectNextState>,
 1268    add_selections_state: Option<AddSelectionsState>,
 1269}
 1270
 1271#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1272enum SelectionHistoryMode {
 1273    Normal,
 1274    Undoing,
 1275    Redoing,
 1276    Skipping,
 1277}
 1278
 1279#[derive(Clone, PartialEq, Eq, Hash)]
 1280struct HoveredCursor {
 1281    replica_id: u16,
 1282    selection_id: usize,
 1283}
 1284
 1285impl Default for SelectionHistoryMode {
 1286    fn default() -> Self {
 1287        Self::Normal
 1288    }
 1289}
 1290
 1291#[derive(Debug)]
 1292/// SelectionEffects controls the side-effects of updating the selection.
 1293///
 1294/// The default behaviour does "what you mostly want":
 1295/// - it pushes to the nav history if the cursor moved by >10 lines
 1296/// - it re-triggers completion requests
 1297/// - it scrolls to fit
 1298///
 1299/// You might want to modify these behaviours. For example when doing a "jump"
 1300/// like go to definition, we always want to add to nav history; but when scrolling
 1301/// in vim mode we never do.
 1302///
 1303/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1304/// move.
 1305pub struct SelectionEffects {
 1306    nav_history: Option<bool>,
 1307    completions: bool,
 1308    scroll: Option<Autoscroll>,
 1309}
 1310
 1311impl Default for SelectionEffects {
 1312    fn default() -> Self {
 1313        Self {
 1314            nav_history: None,
 1315            completions: true,
 1316            scroll: Some(Autoscroll::fit()),
 1317        }
 1318    }
 1319}
 1320impl SelectionEffects {
 1321    pub fn scroll(scroll: Autoscroll) -> Self {
 1322        Self {
 1323            scroll: Some(scroll),
 1324            ..Default::default()
 1325        }
 1326    }
 1327
 1328    pub fn no_scroll() -> Self {
 1329        Self {
 1330            scroll: None,
 1331            ..Default::default()
 1332        }
 1333    }
 1334
 1335    pub fn completions(self, completions: bool) -> Self {
 1336        Self {
 1337            completions,
 1338            ..self
 1339        }
 1340    }
 1341
 1342    pub fn nav_history(self, nav_history: bool) -> Self {
 1343        Self {
 1344            nav_history: Some(nav_history),
 1345            ..self
 1346        }
 1347    }
 1348}
 1349
 1350struct DeferredSelectionEffectsState {
 1351    changed: bool,
 1352    effects: SelectionEffects,
 1353    old_cursor_position: Anchor,
 1354    history_entry: SelectionHistoryEntry,
 1355}
 1356
 1357#[derive(Default)]
 1358struct SelectionHistory {
 1359    #[allow(clippy::type_complexity)]
 1360    selections_by_transaction:
 1361        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1362    mode: SelectionHistoryMode,
 1363    undo_stack: VecDeque<SelectionHistoryEntry>,
 1364    redo_stack: VecDeque<SelectionHistoryEntry>,
 1365}
 1366
 1367impl SelectionHistory {
 1368    #[track_caller]
 1369    fn insert_transaction(
 1370        &mut self,
 1371        transaction_id: TransactionId,
 1372        selections: Arc<[Selection<Anchor>]>,
 1373    ) {
 1374        if selections.is_empty() {
 1375            log::error!(
 1376                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1377                std::panic::Location::caller()
 1378            );
 1379            return;
 1380        }
 1381        self.selections_by_transaction
 1382            .insert(transaction_id, (selections, None));
 1383    }
 1384
 1385    #[allow(clippy::type_complexity)]
 1386    fn transaction(
 1387        &self,
 1388        transaction_id: TransactionId,
 1389    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1390        self.selections_by_transaction.get(&transaction_id)
 1391    }
 1392
 1393    #[allow(clippy::type_complexity)]
 1394    fn transaction_mut(
 1395        &mut self,
 1396        transaction_id: TransactionId,
 1397    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1398        self.selections_by_transaction.get_mut(&transaction_id)
 1399    }
 1400
 1401    fn push(&mut self, entry: SelectionHistoryEntry) {
 1402        if !entry.selections.is_empty() {
 1403            match self.mode {
 1404                SelectionHistoryMode::Normal => {
 1405                    self.push_undo(entry);
 1406                    self.redo_stack.clear();
 1407                }
 1408                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1409                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1410                SelectionHistoryMode::Skipping => {}
 1411            }
 1412        }
 1413    }
 1414
 1415    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1416        if self
 1417            .undo_stack
 1418            .back()
 1419            .map_or(true, |e| e.selections != entry.selections)
 1420        {
 1421            self.undo_stack.push_back(entry);
 1422            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1423                self.undo_stack.pop_front();
 1424            }
 1425        }
 1426    }
 1427
 1428    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1429        if self
 1430            .redo_stack
 1431            .back()
 1432            .map_or(true, |e| e.selections != entry.selections)
 1433        {
 1434            self.redo_stack.push_back(entry);
 1435            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1436                self.redo_stack.pop_front();
 1437            }
 1438        }
 1439    }
 1440}
 1441
 1442#[derive(Clone, Copy)]
 1443pub struct RowHighlightOptions {
 1444    pub autoscroll: bool,
 1445    pub include_gutter: bool,
 1446}
 1447
 1448impl Default for RowHighlightOptions {
 1449    fn default() -> Self {
 1450        Self {
 1451            autoscroll: Default::default(),
 1452            include_gutter: true,
 1453        }
 1454    }
 1455}
 1456
 1457struct RowHighlight {
 1458    index: usize,
 1459    range: Range<Anchor>,
 1460    color: Hsla,
 1461    options: RowHighlightOptions,
 1462    type_id: TypeId,
 1463}
 1464
 1465#[derive(Clone, Debug)]
 1466struct AddSelectionsState {
 1467    groups: Vec<AddSelectionsGroup>,
 1468}
 1469
 1470#[derive(Clone, Debug)]
 1471struct AddSelectionsGroup {
 1472    above: bool,
 1473    stack: Vec<usize>,
 1474}
 1475
 1476#[derive(Clone)]
 1477struct SelectNextState {
 1478    query: AhoCorasick,
 1479    wordwise: bool,
 1480    done: bool,
 1481}
 1482
 1483impl std::fmt::Debug for SelectNextState {
 1484    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1485        f.debug_struct(std::any::type_name::<Self>())
 1486            .field("wordwise", &self.wordwise)
 1487            .field("done", &self.done)
 1488            .finish()
 1489    }
 1490}
 1491
 1492#[derive(Debug)]
 1493struct AutocloseRegion {
 1494    selection_id: usize,
 1495    range: Range<Anchor>,
 1496    pair: BracketPair,
 1497}
 1498
 1499#[derive(Debug)]
 1500struct SnippetState {
 1501    ranges: Vec<Vec<Range<Anchor>>>,
 1502    active_index: usize,
 1503    choices: Vec<Option<Vec<String>>>,
 1504}
 1505
 1506#[doc(hidden)]
 1507pub struct RenameState {
 1508    pub range: Range<Anchor>,
 1509    pub old_name: Arc<str>,
 1510    pub editor: Entity<Editor>,
 1511    block_id: CustomBlockId,
 1512}
 1513
 1514struct InvalidationStack<T>(Vec<T>);
 1515
 1516struct RegisteredInlineCompletionProvider {
 1517    provider: Arc<dyn InlineCompletionProviderHandle>,
 1518    _subscription: Subscription,
 1519}
 1520
 1521#[derive(Debug, PartialEq, Eq)]
 1522pub struct ActiveDiagnosticGroup {
 1523    pub active_range: Range<Anchor>,
 1524    pub active_message: String,
 1525    pub group_id: usize,
 1526    pub blocks: HashSet<CustomBlockId>,
 1527}
 1528
 1529#[derive(Debug, PartialEq, Eq)]
 1530
 1531pub(crate) enum ActiveDiagnostic {
 1532    None,
 1533    All,
 1534    Group(ActiveDiagnosticGroup),
 1535}
 1536
 1537#[derive(Serialize, Deserialize, Clone, Debug)]
 1538pub struct ClipboardSelection {
 1539    /// The number of bytes in this selection.
 1540    pub len: usize,
 1541    /// Whether this was a full-line selection.
 1542    pub is_entire_line: bool,
 1543    /// The indentation of the first line when this content was originally copied.
 1544    pub first_line_indent: u32,
 1545}
 1546
 1547// selections, scroll behavior, was newest selection reversed
 1548type SelectSyntaxNodeHistoryState = (
 1549    Box<[Selection<usize>]>,
 1550    SelectSyntaxNodeScrollBehavior,
 1551    bool,
 1552);
 1553
 1554#[derive(Default)]
 1555struct SelectSyntaxNodeHistory {
 1556    stack: Vec<SelectSyntaxNodeHistoryState>,
 1557    // disable temporarily to allow changing selections without losing the stack
 1558    pub disable_clearing: bool,
 1559}
 1560
 1561impl SelectSyntaxNodeHistory {
 1562    pub fn try_clear(&mut self) {
 1563        if !self.disable_clearing {
 1564            self.stack.clear();
 1565        }
 1566    }
 1567
 1568    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1569        self.stack.push(selection);
 1570    }
 1571
 1572    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1573        self.stack.pop()
 1574    }
 1575}
 1576
 1577enum SelectSyntaxNodeScrollBehavior {
 1578    CursorTop,
 1579    FitSelection,
 1580    CursorBottom,
 1581}
 1582
 1583#[derive(Debug)]
 1584pub(crate) struct NavigationData {
 1585    cursor_anchor: Anchor,
 1586    cursor_position: Point,
 1587    scroll_anchor: ScrollAnchor,
 1588    scroll_top_row: u32,
 1589}
 1590
 1591#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1592pub enum GotoDefinitionKind {
 1593    Symbol,
 1594    Declaration,
 1595    Type,
 1596    Implementation,
 1597}
 1598
 1599#[derive(Debug, Clone)]
 1600enum InlayHintRefreshReason {
 1601    ModifiersChanged(bool),
 1602    Toggle(bool),
 1603    SettingsChange(InlayHintSettings),
 1604    NewLinesShown,
 1605    BufferEdited(HashSet<Arc<Language>>),
 1606    RefreshRequested,
 1607    ExcerptsRemoved(Vec<ExcerptId>),
 1608}
 1609
 1610impl InlayHintRefreshReason {
 1611    fn description(&self) -> &'static str {
 1612        match self {
 1613            Self::ModifiersChanged(_) => "modifiers changed",
 1614            Self::Toggle(_) => "toggle",
 1615            Self::SettingsChange(_) => "settings change",
 1616            Self::NewLinesShown => "new lines shown",
 1617            Self::BufferEdited(_) => "buffer edited",
 1618            Self::RefreshRequested => "refresh requested",
 1619            Self::ExcerptsRemoved(_) => "excerpts removed",
 1620        }
 1621    }
 1622}
 1623
 1624pub enum FormatTarget {
 1625    Buffers(HashSet<Entity<Buffer>>),
 1626    Ranges(Vec<Range<MultiBufferPoint>>),
 1627}
 1628
 1629pub(crate) struct FocusedBlock {
 1630    id: BlockId,
 1631    focus_handle: WeakFocusHandle,
 1632}
 1633
 1634#[derive(Clone)]
 1635enum JumpData {
 1636    MultiBufferRow {
 1637        row: MultiBufferRow,
 1638        line_offset_from_top: u32,
 1639    },
 1640    MultiBufferPoint {
 1641        excerpt_id: ExcerptId,
 1642        position: Point,
 1643        anchor: text::Anchor,
 1644        line_offset_from_top: u32,
 1645    },
 1646}
 1647
 1648pub enum MultibufferSelectionMode {
 1649    First,
 1650    All,
 1651}
 1652
 1653#[derive(Clone, Copy, Debug, Default)]
 1654pub struct RewrapOptions {
 1655    pub override_language_settings: bool,
 1656    pub preserve_existing_whitespace: bool,
 1657}
 1658
 1659impl Editor {
 1660    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1661        let buffer = cx.new(|cx| Buffer::local("", cx));
 1662        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1663        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1664    }
 1665
 1666    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1667        let buffer = cx.new(|cx| Buffer::local("", cx));
 1668        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1669        Self::new(EditorMode::full(), buffer, None, window, cx)
 1670    }
 1671
 1672    pub fn auto_height(
 1673        min_lines: usize,
 1674        max_lines: usize,
 1675        window: &mut Window,
 1676        cx: &mut Context<Self>,
 1677    ) -> Self {
 1678        let buffer = cx.new(|cx| Buffer::local("", cx));
 1679        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1680        Self::new(
 1681            EditorMode::AutoHeight {
 1682                min_lines,
 1683                max_lines: Some(max_lines),
 1684            },
 1685            buffer,
 1686            None,
 1687            window,
 1688            cx,
 1689        )
 1690    }
 1691
 1692    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1693    /// The editor grows as tall as needed to fit its content.
 1694    pub fn auto_height_unbounded(
 1695        min_lines: usize,
 1696        window: &mut Window,
 1697        cx: &mut Context<Self>,
 1698    ) -> Self {
 1699        let buffer = cx.new(|cx| Buffer::local("", cx));
 1700        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1701        Self::new(
 1702            EditorMode::AutoHeight {
 1703                min_lines,
 1704                max_lines: None,
 1705            },
 1706            buffer,
 1707            None,
 1708            window,
 1709            cx,
 1710        )
 1711    }
 1712
 1713    pub fn for_buffer(
 1714        buffer: Entity<Buffer>,
 1715        project: Option<Entity<Project>>,
 1716        window: &mut Window,
 1717        cx: &mut Context<Self>,
 1718    ) -> Self {
 1719        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1720        Self::new(EditorMode::full(), buffer, project, window, cx)
 1721    }
 1722
 1723    pub fn for_multibuffer(
 1724        buffer: Entity<MultiBuffer>,
 1725        project: Option<Entity<Project>>,
 1726        window: &mut Window,
 1727        cx: &mut Context<Self>,
 1728    ) -> Self {
 1729        Self::new(EditorMode::full(), buffer, project, window, cx)
 1730    }
 1731
 1732    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1733        let mut clone = Self::new(
 1734            self.mode.clone(),
 1735            self.buffer.clone(),
 1736            self.project.clone(),
 1737            window,
 1738            cx,
 1739        );
 1740        self.display_map.update(cx, |display_map, cx| {
 1741            let snapshot = display_map.snapshot(cx);
 1742            clone.display_map.update(cx, |display_map, cx| {
 1743                display_map.set_state(&snapshot, cx);
 1744            });
 1745        });
 1746        clone.folds_did_change(cx);
 1747        clone.selections.clone_state(&self.selections);
 1748        clone.scroll_manager.clone_state(&self.scroll_manager);
 1749        clone.searchable = self.searchable;
 1750        clone.read_only = self.read_only;
 1751        clone
 1752    }
 1753
 1754    pub fn new(
 1755        mode: EditorMode,
 1756        buffer: Entity<MultiBuffer>,
 1757        project: Option<Entity<Project>>,
 1758        window: &mut Window,
 1759        cx: &mut Context<Self>,
 1760    ) -> Self {
 1761        Editor::new_internal(mode, buffer, project, None, window, cx)
 1762    }
 1763
 1764    fn new_internal(
 1765        mode: EditorMode,
 1766        buffer: Entity<MultiBuffer>,
 1767        project: Option<Entity<Project>>,
 1768        display_map: Option<Entity<DisplayMap>>,
 1769        window: &mut Window,
 1770        cx: &mut Context<Self>,
 1771    ) -> Self {
 1772        debug_assert!(
 1773            display_map.is_none() || mode.is_minimap(),
 1774            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1775        );
 1776
 1777        let full_mode = mode.is_full();
 1778        let diagnostics_max_severity = if full_mode {
 1779            EditorSettings::get_global(cx)
 1780                .diagnostics_max_severity
 1781                .unwrap_or(DiagnosticSeverity::Hint)
 1782        } else {
 1783            DiagnosticSeverity::Off
 1784        };
 1785        let style = window.text_style();
 1786        let font_size = style.font_size.to_pixels(window.rem_size());
 1787        let editor = cx.entity().downgrade();
 1788        let fold_placeholder = FoldPlaceholder {
 1789            constrain_width: true,
 1790            render: Arc::new(move |fold_id, fold_range, cx| {
 1791                let editor = editor.clone();
 1792                div()
 1793                    .id(fold_id)
 1794                    .bg(cx.theme().colors().ghost_element_background)
 1795                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1796                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1797                    .rounded_xs()
 1798                    .size_full()
 1799                    .cursor_pointer()
 1800                    .child("")
 1801                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1802                    .on_click(move |_, _window, cx| {
 1803                        editor
 1804                            .update(cx, |editor, cx| {
 1805                                editor.unfold_ranges(
 1806                                    &[fold_range.start..fold_range.end],
 1807                                    true,
 1808                                    false,
 1809                                    cx,
 1810                                );
 1811                                cx.stop_propagation();
 1812                            })
 1813                            .ok();
 1814                    })
 1815                    .into_any()
 1816            }),
 1817            merge_adjacent: true,
 1818            ..FoldPlaceholder::default()
 1819        };
 1820        let display_map = display_map.unwrap_or_else(|| {
 1821            cx.new(|cx| {
 1822                DisplayMap::new(
 1823                    buffer.clone(),
 1824                    style.font(),
 1825                    font_size,
 1826                    None,
 1827                    FILE_HEADER_HEIGHT,
 1828                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1829                    fold_placeholder,
 1830                    diagnostics_max_severity,
 1831                    cx,
 1832                )
 1833            })
 1834        });
 1835
 1836        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1837
 1838        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1839
 1840        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1841            .then(|| language_settings::SoftWrap::None);
 1842
 1843        let mut project_subscriptions = Vec::new();
 1844        if mode.is_full() {
 1845            if let Some(project) = project.as_ref() {
 1846                project_subscriptions.push(cx.subscribe_in(
 1847                    project,
 1848                    window,
 1849                    |editor, _, event, window, cx| match event {
 1850                        project::Event::RefreshCodeLens => {
 1851                            // we always query lens with actions, without storing them, always refreshing them
 1852                        }
 1853                        project::Event::RefreshInlayHints => {
 1854                            editor
 1855                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1856                        }
 1857                        project::Event::LanguageServerAdded(..)
 1858                        | project::Event::LanguageServerRemoved(..) => {
 1859                            if editor.tasks_update_task.is_none() {
 1860                                editor.tasks_update_task =
 1861                                    Some(editor.refresh_runnables(window, cx));
 1862                            }
 1863                            editor.update_lsp_data(true, None, window, cx);
 1864                        }
 1865                        project::Event::SnippetEdit(id, snippet_edits) => {
 1866                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1867                                let focus_handle = editor.focus_handle(cx);
 1868                                if focus_handle.is_focused(window) {
 1869                                    let snapshot = buffer.read(cx).snapshot();
 1870                                    for (range, snippet) in snippet_edits {
 1871                                        let editor_range =
 1872                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1873                                        editor
 1874                                            .insert_snippet(
 1875                                                &[editor_range],
 1876                                                snippet.clone(),
 1877                                                window,
 1878                                                cx,
 1879                                            )
 1880                                            .ok();
 1881                                    }
 1882                                }
 1883                            }
 1884                        }
 1885                        _ => {}
 1886                    },
 1887                ));
 1888                if let Some(task_inventory) = project
 1889                    .read(cx)
 1890                    .task_store()
 1891                    .read(cx)
 1892                    .task_inventory()
 1893                    .cloned()
 1894                {
 1895                    project_subscriptions.push(cx.observe_in(
 1896                        &task_inventory,
 1897                        window,
 1898                        |editor, _, window, cx| {
 1899                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1900                        },
 1901                    ));
 1902                };
 1903
 1904                project_subscriptions.push(cx.subscribe_in(
 1905                    &project.read(cx).breakpoint_store(),
 1906                    window,
 1907                    |editor, _, event, window, cx| match event {
 1908                        BreakpointStoreEvent::ClearDebugLines => {
 1909                            editor.clear_row_highlights::<ActiveDebugLine>();
 1910                            editor.refresh_inline_values(cx);
 1911                        }
 1912                        BreakpointStoreEvent::SetDebugLine => {
 1913                            if editor.go_to_active_debug_line(window, cx) {
 1914                                cx.stop_propagation();
 1915                            }
 1916
 1917                            editor.refresh_inline_values(cx);
 1918                        }
 1919                        _ => {}
 1920                    },
 1921                ));
 1922                let git_store = project.read(cx).git_store().clone();
 1923                let project = project.clone();
 1924                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1925                    match event {
 1926                        GitStoreEvent::RepositoryUpdated(
 1927                            _,
 1928                            RepositoryEvent::Updated {
 1929                                new_instance: true, ..
 1930                            },
 1931                            _,
 1932                        ) => {
 1933                            this.load_diff_task = Some(
 1934                                update_uncommitted_diff_for_buffer(
 1935                                    cx.entity(),
 1936                                    &project,
 1937                                    this.buffer.read(cx).all_buffers(),
 1938                                    this.buffer.clone(),
 1939                                    cx,
 1940                                )
 1941                                .shared(),
 1942                            );
 1943                        }
 1944                        _ => {}
 1945                    }
 1946                }));
 1947            }
 1948        }
 1949
 1950        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1951
 1952        let inlay_hint_settings =
 1953            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1954        let focus_handle = cx.focus_handle();
 1955        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1956            .detach();
 1957        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1958            .detach();
 1959        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1960            .detach();
 1961        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1962            .detach();
 1963        cx.observe_pending_input(window, Self::observe_pending_input)
 1964            .detach();
 1965
 1966        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1967            Some(false)
 1968        } else {
 1969            None
 1970        };
 1971
 1972        let breakpoint_store = match (&mode, project.as_ref()) {
 1973            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1974            _ => None,
 1975        };
 1976
 1977        let mut code_action_providers = Vec::new();
 1978        let mut load_uncommitted_diff = None;
 1979        if let Some(project) = project.clone() {
 1980            load_uncommitted_diff = Some(
 1981                update_uncommitted_diff_for_buffer(
 1982                    cx.entity(),
 1983                    &project,
 1984                    buffer.read(cx).all_buffers(),
 1985                    buffer.clone(),
 1986                    cx,
 1987                )
 1988                .shared(),
 1989            );
 1990            code_action_providers.push(Rc::new(project) as Rc<_>);
 1991        }
 1992
 1993        let mut editor = Self {
 1994            focus_handle,
 1995            show_cursor_when_unfocused: false,
 1996            last_focused_descendant: None,
 1997            buffer: buffer.clone(),
 1998            display_map: display_map.clone(),
 1999            selections,
 2000            scroll_manager: ScrollManager::new(cx),
 2001            columnar_selection_state: None,
 2002            add_selections_state: None,
 2003            select_next_state: None,
 2004            select_prev_state: None,
 2005            selection_history: SelectionHistory::default(),
 2006            defer_selection_effects: false,
 2007            deferred_selection_effects_state: None,
 2008            autoclose_regions: Vec::new(),
 2009            snippet_stack: InvalidationStack::default(),
 2010            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2011            ime_transaction: None,
 2012            active_diagnostics: ActiveDiagnostic::None,
 2013            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2014            inline_diagnostics_update: Task::ready(()),
 2015            inline_diagnostics: Vec::new(),
 2016            soft_wrap_mode_override,
 2017            diagnostics_max_severity,
 2018            hard_wrap: None,
 2019            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2020            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2021            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2022            project,
 2023            blink_manager: blink_manager.clone(),
 2024            show_local_selections: true,
 2025            show_scrollbars: ScrollbarAxes {
 2026                horizontal: full_mode,
 2027                vertical: full_mode,
 2028            },
 2029            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2030            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2031            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2032            show_gutter: mode.is_full(),
 2033            show_line_numbers: None,
 2034            use_relative_line_numbers: None,
 2035            disable_expand_excerpt_buttons: false,
 2036            show_git_diff_gutter: None,
 2037            show_code_actions: None,
 2038            show_runnables: None,
 2039            show_breakpoints: None,
 2040            show_wrap_guides: None,
 2041            show_indent_guides,
 2042            placeholder_text: None,
 2043            highlight_order: 0,
 2044            highlighted_rows: HashMap::default(),
 2045            background_highlights: TreeMap::default(),
 2046            gutter_highlights: TreeMap::default(),
 2047            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2048            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2049            nav_history: None,
 2050            context_menu: RefCell::new(None),
 2051            context_menu_options: None,
 2052            mouse_context_menu: None,
 2053            completion_tasks: Vec::new(),
 2054            inline_blame_popover: None,
 2055            inline_blame_popover_show_task: None,
 2056            signature_help_state: SignatureHelpState::default(),
 2057            auto_signature_help: None,
 2058            find_all_references_task_sources: Vec::new(),
 2059            next_completion_id: 0,
 2060            next_inlay_id: 0,
 2061            code_action_providers,
 2062            available_code_actions: None,
 2063            code_actions_task: None,
 2064            quick_selection_highlight_task: None,
 2065            debounced_selection_highlight_task: None,
 2066            document_highlights_task: None,
 2067            linked_editing_range_task: None,
 2068            pending_rename: None,
 2069            searchable: true,
 2070            cursor_shape: EditorSettings::get_global(cx)
 2071                .cursor_shape
 2072                .unwrap_or_default(),
 2073            current_line_highlight: None,
 2074            autoindent_mode: Some(AutoindentMode::EachLine),
 2075            collapse_matches: false,
 2076            workspace: None,
 2077            input_enabled: true,
 2078            use_modal_editing: mode.is_full(),
 2079            read_only: mode.is_minimap(),
 2080            use_autoclose: true,
 2081            use_auto_surround: true,
 2082            auto_replace_emoji_shortcode: false,
 2083            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2084            leader_id: None,
 2085            remote_id: None,
 2086            hover_state: HoverState::default(),
 2087            pending_mouse_down: None,
 2088            hovered_link_state: None,
 2089            edit_prediction_provider: None,
 2090            active_inline_completion: None,
 2091            stale_inline_completion_in_menu: None,
 2092            edit_prediction_preview: EditPredictionPreview::Inactive {
 2093                released_too_fast: false,
 2094            },
 2095            inline_diagnostics_enabled: mode.is_full(),
 2096            diagnostics_enabled: mode.is_full(),
 2097            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2098            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2099
 2100            gutter_hovered: false,
 2101            pixel_position_of_newest_cursor: None,
 2102            last_bounds: None,
 2103            last_position_map: None,
 2104            expect_bounds_change: None,
 2105            gutter_dimensions: GutterDimensions::default(),
 2106            style: None,
 2107            show_cursor_names: false,
 2108            hovered_cursors: HashMap::default(),
 2109            next_editor_action_id: EditorActionId::default(),
 2110            editor_actions: Rc::default(),
 2111            inline_completions_hidden_for_vim_mode: false,
 2112            show_inline_completions_override: None,
 2113            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2114            edit_prediction_settings: EditPredictionSettings::Disabled,
 2115            edit_prediction_indent_conflict: false,
 2116            edit_prediction_requires_modifier_in_indent_conflict: true,
 2117            custom_context_menu: None,
 2118            show_git_blame_gutter: false,
 2119            show_git_blame_inline: false,
 2120            show_selection_menu: None,
 2121            show_git_blame_inline_delay_task: None,
 2122            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2123            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2124            serialize_dirty_buffers: !mode.is_minimap()
 2125                && ProjectSettings::get_global(cx)
 2126                    .session
 2127                    .restore_unsaved_buffers,
 2128            blame: None,
 2129            blame_subscription: None,
 2130            tasks: BTreeMap::default(),
 2131
 2132            breakpoint_store,
 2133            gutter_breakpoint_indicator: (None, None),
 2134            hovered_diff_hunk_row: None,
 2135            _subscriptions: vec![
 2136                cx.observe(&buffer, Self::on_buffer_changed),
 2137                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2138                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2139                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2140                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2141                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2142                cx.observe_window_activation(window, |editor, window, cx| {
 2143                    let active = window.is_window_active();
 2144                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2145                        if active {
 2146                            blink_manager.enable(cx);
 2147                        } else {
 2148                            blink_manager.disable(cx);
 2149                        }
 2150                    });
 2151                    if active {
 2152                        editor.show_mouse_cursor(cx);
 2153                    }
 2154                }),
 2155            ],
 2156            tasks_update_task: None,
 2157            pull_diagnostics_task: Task::ready(()),
 2158            colors: None,
 2159            next_color_inlay_id: 0,
 2160            linked_edit_ranges: Default::default(),
 2161            in_project_search: false,
 2162            previous_search_ranges: None,
 2163            breadcrumb_header: None,
 2164            focused_block: None,
 2165            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2166            addons: HashMap::default(),
 2167            registered_buffers: HashMap::default(),
 2168            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2169            selection_mark_mode: false,
 2170            toggle_fold_multiple_buffers: Task::ready(()),
 2171            serialize_selections: Task::ready(()),
 2172            serialize_folds: Task::ready(()),
 2173            text_style_refinement: None,
 2174            load_diff_task: load_uncommitted_diff,
 2175            temporary_diff_override: false,
 2176            mouse_cursor_hidden: false,
 2177            minimap: None,
 2178            hide_mouse_mode: EditorSettings::get_global(cx)
 2179                .hide_mouse
 2180                .unwrap_or_default(),
 2181            change_list: ChangeList::new(),
 2182            mode,
 2183            selection_drag_state: SelectionDragState::None,
 2184            folding_newlines: Task::ready(()),
 2185        };
 2186        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2187            editor
 2188                ._subscriptions
 2189                .push(cx.observe(breakpoints, |_, _, cx| {
 2190                    cx.notify();
 2191                }));
 2192        }
 2193        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2194        editor._subscriptions.extend(project_subscriptions);
 2195
 2196        editor._subscriptions.push(cx.subscribe_in(
 2197            &cx.entity(),
 2198            window,
 2199            |editor, _, e: &EditorEvent, window, cx| match e {
 2200                EditorEvent::ScrollPositionChanged { local, .. } => {
 2201                    if *local {
 2202                        let new_anchor = editor.scroll_manager.anchor();
 2203                        let snapshot = editor.snapshot(window, cx);
 2204                        editor.update_restoration_data(cx, move |data| {
 2205                            data.scroll_position = (
 2206                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2207                                new_anchor.offset,
 2208                            );
 2209                        });
 2210                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2211                        editor.inline_blame_popover.take();
 2212                    }
 2213                }
 2214                EditorEvent::Edited { .. } => {
 2215                    if !vim_enabled(cx) {
 2216                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2217                        let pop_state = editor
 2218                            .change_list
 2219                            .last()
 2220                            .map(|previous| {
 2221                                previous.len() == selections.len()
 2222                                    && previous.iter().enumerate().all(|(ix, p)| {
 2223                                        p.to_display_point(&map).row()
 2224                                            == selections[ix].head().row()
 2225                                    })
 2226                            })
 2227                            .unwrap_or(false);
 2228                        let new_positions = selections
 2229                            .into_iter()
 2230                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2231                            .collect();
 2232                        editor
 2233                            .change_list
 2234                            .push_to_change_list(pop_state, new_positions);
 2235                    }
 2236                }
 2237                _ => (),
 2238            },
 2239        ));
 2240
 2241        if let Some(dap_store) = editor
 2242            .project
 2243            .as_ref()
 2244            .map(|project| project.read(cx).dap_store())
 2245        {
 2246            let weak_editor = cx.weak_entity();
 2247
 2248            editor
 2249                ._subscriptions
 2250                .push(
 2251                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2252                        let session_entity = cx.entity();
 2253                        weak_editor
 2254                            .update(cx, |editor, cx| {
 2255                                editor._subscriptions.push(
 2256                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2257                                );
 2258                            })
 2259                            .ok();
 2260                    }),
 2261                );
 2262
 2263            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2264                editor
 2265                    ._subscriptions
 2266                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2267            }
 2268        }
 2269
 2270        // skip adding the initial selection to selection history
 2271        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2272        editor.end_selection(window, cx);
 2273        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2274
 2275        editor.scroll_manager.show_scrollbars(window, cx);
 2276        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2277
 2278        if full_mode {
 2279            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2280            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2281
 2282            if editor.git_blame_inline_enabled {
 2283                editor.start_git_blame_inline(false, window, cx);
 2284            }
 2285
 2286            editor.go_to_active_debug_line(window, cx);
 2287
 2288            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2289                if let Some(project) = editor.project.as_ref() {
 2290                    let handle = project.update(cx, |project, cx| {
 2291                        project.register_buffer_with_language_servers(&buffer, cx)
 2292                    });
 2293                    editor
 2294                        .registered_buffers
 2295                        .insert(buffer.read(cx).remote_id(), handle);
 2296                }
 2297            }
 2298
 2299            editor.minimap =
 2300                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2301            editor.colors = Some(LspColorData::new(cx));
 2302            editor.update_lsp_data(false, None, window, cx);
 2303        }
 2304
 2305        editor.report_editor_event("Editor Opened", None, cx);
 2306        editor
 2307    }
 2308
 2309    pub fn deploy_mouse_context_menu(
 2310        &mut self,
 2311        position: gpui::Point<Pixels>,
 2312        context_menu: Entity<ContextMenu>,
 2313        window: &mut Window,
 2314        cx: &mut Context<Self>,
 2315    ) {
 2316        self.mouse_context_menu = Some(MouseContextMenu::new(
 2317            self,
 2318            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2319            context_menu,
 2320            window,
 2321            cx,
 2322        ));
 2323    }
 2324
 2325    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2326        self.mouse_context_menu
 2327            .as_ref()
 2328            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2329    }
 2330
 2331    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2332        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2333    }
 2334
 2335    fn key_context_internal(
 2336        &self,
 2337        has_active_edit_prediction: bool,
 2338        window: &Window,
 2339        cx: &App,
 2340    ) -> KeyContext {
 2341        let mut key_context = KeyContext::new_with_defaults();
 2342        key_context.add("Editor");
 2343        let mode = match self.mode {
 2344            EditorMode::SingleLine { .. } => "single_line",
 2345            EditorMode::AutoHeight { .. } => "auto_height",
 2346            EditorMode::Minimap { .. } => "minimap",
 2347            EditorMode::Full { .. } => "full",
 2348        };
 2349
 2350        if EditorSettings::jupyter_enabled(cx) {
 2351            key_context.add("jupyter");
 2352        }
 2353
 2354        key_context.set("mode", mode);
 2355        if self.pending_rename.is_some() {
 2356            key_context.add("renaming");
 2357        }
 2358
 2359        match self.context_menu.borrow().as_ref() {
 2360            Some(CodeContextMenu::Completions(_)) => {
 2361                key_context.add("menu");
 2362                key_context.add("showing_completions");
 2363            }
 2364            Some(CodeContextMenu::CodeActions(_)) => {
 2365                key_context.add("menu");
 2366                key_context.add("showing_code_actions")
 2367            }
 2368            None => {}
 2369        }
 2370
 2371        if self.signature_help_state.has_multiple_signatures() {
 2372            key_context.add("showing_signature_help");
 2373        }
 2374
 2375        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2376        if !self.focus_handle(cx).contains_focused(window, cx)
 2377            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2378        {
 2379            for addon in self.addons.values() {
 2380                addon.extend_key_context(&mut key_context, cx)
 2381            }
 2382        }
 2383
 2384        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2385            if let Some(extension) = singleton_buffer
 2386                .read(cx)
 2387                .file()
 2388                .and_then(|file| file.path().extension()?.to_str())
 2389            {
 2390                key_context.set("extension", extension.to_string());
 2391            }
 2392        } else {
 2393            key_context.add("multibuffer");
 2394        }
 2395
 2396        if has_active_edit_prediction {
 2397            if self.edit_prediction_in_conflict() {
 2398                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2399            } else {
 2400                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2401                key_context.add("copilot_suggestion");
 2402            }
 2403        }
 2404
 2405        if self.selection_mark_mode {
 2406            key_context.add("selection_mode");
 2407        }
 2408
 2409        key_context
 2410    }
 2411
 2412    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2413        if self.mouse_cursor_hidden {
 2414            self.mouse_cursor_hidden = false;
 2415            cx.notify();
 2416        }
 2417    }
 2418
 2419    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2420        let hide_mouse_cursor = match origin {
 2421            HideMouseCursorOrigin::TypingAction => {
 2422                matches!(
 2423                    self.hide_mouse_mode,
 2424                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2425                )
 2426            }
 2427            HideMouseCursorOrigin::MovementAction => {
 2428                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2429            }
 2430        };
 2431        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2432            self.mouse_cursor_hidden = hide_mouse_cursor;
 2433            cx.notify();
 2434        }
 2435    }
 2436
 2437    pub fn edit_prediction_in_conflict(&self) -> bool {
 2438        if !self.show_edit_predictions_in_menu() {
 2439            return false;
 2440        }
 2441
 2442        let showing_completions = self
 2443            .context_menu
 2444            .borrow()
 2445            .as_ref()
 2446            .map_or(false, |context| {
 2447                matches!(context, CodeContextMenu::Completions(_))
 2448            });
 2449
 2450        showing_completions
 2451            || self.edit_prediction_requires_modifier()
 2452            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2453            // bindings to insert tab characters.
 2454            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2455    }
 2456
 2457    pub fn accept_edit_prediction_keybind(
 2458        &self,
 2459        accept_partial: bool,
 2460        window: &Window,
 2461        cx: &App,
 2462    ) -> AcceptEditPredictionBinding {
 2463        let key_context = self.key_context_internal(true, window, cx);
 2464        let in_conflict = self.edit_prediction_in_conflict();
 2465
 2466        let bindings = if accept_partial {
 2467            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2468        } else {
 2469            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2470        };
 2471
 2472        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2473        // just the first one.
 2474        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2475            !in_conflict
 2476                || binding
 2477                    .keystrokes()
 2478                    .first()
 2479                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2480        }))
 2481    }
 2482
 2483    pub fn new_file(
 2484        workspace: &mut Workspace,
 2485        _: &workspace::NewFile,
 2486        window: &mut Window,
 2487        cx: &mut Context<Workspace>,
 2488    ) {
 2489        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2490            "Failed to create buffer",
 2491            window,
 2492            cx,
 2493            |e, _, _| match e.error_code() {
 2494                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2495                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2496                e.error_tag("required").unwrap_or("the latest version")
 2497            )),
 2498                _ => None,
 2499            },
 2500        );
 2501    }
 2502
 2503    pub fn new_in_workspace(
 2504        workspace: &mut Workspace,
 2505        window: &mut Window,
 2506        cx: &mut Context<Workspace>,
 2507    ) -> Task<Result<Entity<Editor>>> {
 2508        let project = workspace.project().clone();
 2509        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2510
 2511        cx.spawn_in(window, async move |workspace, cx| {
 2512            let buffer = create.await?;
 2513            workspace.update_in(cx, |workspace, window, cx| {
 2514                let editor =
 2515                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2516                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2517                editor
 2518            })
 2519        })
 2520    }
 2521
 2522    fn new_file_vertical(
 2523        workspace: &mut Workspace,
 2524        _: &workspace::NewFileSplitVertical,
 2525        window: &mut Window,
 2526        cx: &mut Context<Workspace>,
 2527    ) {
 2528        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2529    }
 2530
 2531    fn new_file_horizontal(
 2532        workspace: &mut Workspace,
 2533        _: &workspace::NewFileSplitHorizontal,
 2534        window: &mut Window,
 2535        cx: &mut Context<Workspace>,
 2536    ) {
 2537        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2538    }
 2539
 2540    fn new_file_in_direction(
 2541        workspace: &mut Workspace,
 2542        direction: SplitDirection,
 2543        window: &mut Window,
 2544        cx: &mut Context<Workspace>,
 2545    ) {
 2546        let project = workspace.project().clone();
 2547        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2548
 2549        cx.spawn_in(window, async move |workspace, cx| {
 2550            let buffer = create.await?;
 2551            workspace.update_in(cx, move |workspace, window, cx| {
 2552                workspace.split_item(
 2553                    direction,
 2554                    Box::new(
 2555                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2556                    ),
 2557                    window,
 2558                    cx,
 2559                )
 2560            })?;
 2561            anyhow::Ok(())
 2562        })
 2563        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2564            match e.error_code() {
 2565                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2566                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2567                e.error_tag("required").unwrap_or("the latest version")
 2568            )),
 2569                _ => None,
 2570            }
 2571        });
 2572    }
 2573
 2574    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2575        self.leader_id
 2576    }
 2577
 2578    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2579        &self.buffer
 2580    }
 2581
 2582    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2583        self.workspace.as_ref()?.0.upgrade()
 2584    }
 2585
 2586    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2587        self.buffer().read(cx).title(cx)
 2588    }
 2589
 2590    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2591        let git_blame_gutter_max_author_length = self
 2592            .render_git_blame_gutter(cx)
 2593            .then(|| {
 2594                if let Some(blame) = self.blame.as_ref() {
 2595                    let max_author_length =
 2596                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2597                    Some(max_author_length)
 2598                } else {
 2599                    None
 2600                }
 2601            })
 2602            .flatten();
 2603
 2604        EditorSnapshot {
 2605            mode: self.mode.clone(),
 2606            show_gutter: self.show_gutter,
 2607            show_line_numbers: self.show_line_numbers,
 2608            show_git_diff_gutter: self.show_git_diff_gutter,
 2609            show_code_actions: self.show_code_actions,
 2610            show_runnables: self.show_runnables,
 2611            show_breakpoints: self.show_breakpoints,
 2612            git_blame_gutter_max_author_length,
 2613            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2614            scroll_anchor: self.scroll_manager.anchor(),
 2615            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2616            placeholder_text: self.placeholder_text.clone(),
 2617            is_focused: self.focus_handle.is_focused(window),
 2618            current_line_highlight: self
 2619                .current_line_highlight
 2620                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2621            gutter_hovered: self.gutter_hovered,
 2622        }
 2623    }
 2624
 2625    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2626        self.buffer.read(cx).language_at(point, cx)
 2627    }
 2628
 2629    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2630        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2631    }
 2632
 2633    pub fn active_excerpt(
 2634        &self,
 2635        cx: &App,
 2636    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2637        self.buffer
 2638            .read(cx)
 2639            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2640    }
 2641
 2642    pub fn mode(&self) -> &EditorMode {
 2643        &self.mode
 2644    }
 2645
 2646    pub fn set_mode(&mut self, mode: EditorMode) {
 2647        self.mode = mode;
 2648    }
 2649
 2650    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2651        self.collaboration_hub.as_deref()
 2652    }
 2653
 2654    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2655        self.collaboration_hub = Some(hub);
 2656    }
 2657
 2658    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2659        self.in_project_search = in_project_search;
 2660    }
 2661
 2662    pub fn set_custom_context_menu(
 2663        &mut self,
 2664        f: impl 'static
 2665        + Fn(
 2666            &mut Self,
 2667            DisplayPoint,
 2668            &mut Window,
 2669            &mut Context<Self>,
 2670        ) -> Option<Entity<ui::ContextMenu>>,
 2671    ) {
 2672        self.custom_context_menu = Some(Box::new(f))
 2673    }
 2674
 2675    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2676        self.completion_provider = provider;
 2677    }
 2678
 2679    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2680        self.semantics_provider.clone()
 2681    }
 2682
 2683    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2684        self.semantics_provider = provider;
 2685    }
 2686
 2687    pub fn set_edit_prediction_provider<T>(
 2688        &mut self,
 2689        provider: Option<Entity<T>>,
 2690        window: &mut Window,
 2691        cx: &mut Context<Self>,
 2692    ) where
 2693        T: EditPredictionProvider,
 2694    {
 2695        self.edit_prediction_provider =
 2696            provider.map(|provider| RegisteredInlineCompletionProvider {
 2697                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2698                    if this.focus_handle.is_focused(window) {
 2699                        this.update_visible_inline_completion(window, cx);
 2700                    }
 2701                }),
 2702                provider: Arc::new(provider),
 2703            });
 2704        self.update_edit_prediction_settings(cx);
 2705        self.refresh_inline_completion(false, false, window, cx);
 2706    }
 2707
 2708    pub fn placeholder_text(&self) -> Option<&str> {
 2709        self.placeholder_text.as_deref()
 2710    }
 2711
 2712    pub fn set_placeholder_text(
 2713        &mut self,
 2714        placeholder_text: impl Into<Arc<str>>,
 2715        cx: &mut Context<Self>,
 2716    ) {
 2717        let placeholder_text = Some(placeholder_text.into());
 2718        if self.placeholder_text != placeholder_text {
 2719            self.placeholder_text = placeholder_text;
 2720            cx.notify();
 2721        }
 2722    }
 2723
 2724    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2725        self.cursor_shape = cursor_shape;
 2726
 2727        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2728        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2729
 2730        cx.notify();
 2731    }
 2732
 2733    pub fn set_current_line_highlight(
 2734        &mut self,
 2735        current_line_highlight: Option<CurrentLineHighlight>,
 2736    ) {
 2737        self.current_line_highlight = current_line_highlight;
 2738    }
 2739
 2740    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2741        self.collapse_matches = collapse_matches;
 2742    }
 2743
 2744    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2745        let buffers = self.buffer.read(cx).all_buffers();
 2746        let Some(project) = self.project.as_ref() else {
 2747            return;
 2748        };
 2749        project.update(cx, |project, cx| {
 2750            for buffer in buffers {
 2751                self.registered_buffers
 2752                    .entry(buffer.read(cx).remote_id())
 2753                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2754            }
 2755        })
 2756    }
 2757
 2758    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2759        if self.collapse_matches {
 2760            return range.start..range.start;
 2761        }
 2762        range.clone()
 2763    }
 2764
 2765    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2766        if self.display_map.read(cx).clip_at_line_ends != clip {
 2767            self.display_map
 2768                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2769        }
 2770    }
 2771
 2772    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2773        self.input_enabled = input_enabled;
 2774    }
 2775
 2776    pub fn set_inline_completions_hidden_for_vim_mode(
 2777        &mut self,
 2778        hidden: bool,
 2779        window: &mut Window,
 2780        cx: &mut Context<Self>,
 2781    ) {
 2782        if hidden != self.inline_completions_hidden_for_vim_mode {
 2783            self.inline_completions_hidden_for_vim_mode = hidden;
 2784            if hidden {
 2785                self.update_visible_inline_completion(window, cx);
 2786            } else {
 2787                self.refresh_inline_completion(true, false, window, cx);
 2788            }
 2789        }
 2790    }
 2791
 2792    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2793        self.menu_inline_completions_policy = value;
 2794    }
 2795
 2796    pub fn set_autoindent(&mut self, autoindent: bool) {
 2797        if autoindent {
 2798            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2799        } else {
 2800            self.autoindent_mode = None;
 2801        }
 2802    }
 2803
 2804    pub fn read_only(&self, cx: &App) -> bool {
 2805        self.read_only || self.buffer.read(cx).read_only()
 2806    }
 2807
 2808    pub fn set_read_only(&mut self, read_only: bool) {
 2809        self.read_only = read_only;
 2810    }
 2811
 2812    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2813        self.use_autoclose = autoclose;
 2814    }
 2815
 2816    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2817        self.use_auto_surround = auto_surround;
 2818    }
 2819
 2820    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2821        self.auto_replace_emoji_shortcode = auto_replace;
 2822    }
 2823
 2824    pub fn toggle_edit_predictions(
 2825        &mut self,
 2826        _: &ToggleEditPrediction,
 2827        window: &mut Window,
 2828        cx: &mut Context<Self>,
 2829    ) {
 2830        if self.show_inline_completions_override.is_some() {
 2831            self.set_show_edit_predictions(None, window, cx);
 2832        } else {
 2833            let show_edit_predictions = !self.edit_predictions_enabled();
 2834            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2835        }
 2836    }
 2837
 2838    pub fn set_show_edit_predictions(
 2839        &mut self,
 2840        show_edit_predictions: Option<bool>,
 2841        window: &mut Window,
 2842        cx: &mut Context<Self>,
 2843    ) {
 2844        self.show_inline_completions_override = show_edit_predictions;
 2845        self.update_edit_prediction_settings(cx);
 2846
 2847        if let Some(false) = show_edit_predictions {
 2848            self.discard_inline_completion(false, cx);
 2849        } else {
 2850            self.refresh_inline_completion(false, true, window, cx);
 2851        }
 2852    }
 2853
 2854    fn inline_completions_disabled_in_scope(
 2855        &self,
 2856        buffer: &Entity<Buffer>,
 2857        buffer_position: language::Anchor,
 2858        cx: &App,
 2859    ) -> bool {
 2860        let snapshot = buffer.read(cx).snapshot();
 2861        let settings = snapshot.settings_at(buffer_position, cx);
 2862
 2863        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2864            return false;
 2865        };
 2866
 2867        scope.override_name().map_or(false, |scope_name| {
 2868            settings
 2869                .edit_predictions_disabled_in
 2870                .iter()
 2871                .any(|s| s == scope_name)
 2872        })
 2873    }
 2874
 2875    pub fn set_use_modal_editing(&mut self, to: bool) {
 2876        self.use_modal_editing = to;
 2877    }
 2878
 2879    pub fn use_modal_editing(&self) -> bool {
 2880        self.use_modal_editing
 2881    }
 2882
 2883    fn selections_did_change(
 2884        &mut self,
 2885        local: bool,
 2886        old_cursor_position: &Anchor,
 2887        effects: SelectionEffects,
 2888        window: &mut Window,
 2889        cx: &mut Context<Self>,
 2890    ) {
 2891        window.invalidate_character_coordinates();
 2892
 2893        // Copy selections to primary selection buffer
 2894        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2895        if local {
 2896            let selections = self.selections.all::<usize>(cx);
 2897            let buffer_handle = self.buffer.read(cx).read(cx);
 2898
 2899            let mut text = String::new();
 2900            for (index, selection) in selections.iter().enumerate() {
 2901                let text_for_selection = buffer_handle
 2902                    .text_for_range(selection.start..selection.end)
 2903                    .collect::<String>();
 2904
 2905                text.push_str(&text_for_selection);
 2906                if index != selections.len() - 1 {
 2907                    text.push('\n');
 2908                }
 2909            }
 2910
 2911            if !text.is_empty() {
 2912                cx.write_to_primary(ClipboardItem::new_string(text));
 2913            }
 2914        }
 2915
 2916        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2917            self.buffer.update(cx, |buffer, cx| {
 2918                buffer.set_active_selections(
 2919                    &self.selections.disjoint_anchors(),
 2920                    self.selections.line_mode,
 2921                    self.cursor_shape,
 2922                    cx,
 2923                )
 2924            });
 2925        }
 2926        let display_map = self
 2927            .display_map
 2928            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2929        let buffer = &display_map.buffer_snapshot;
 2930        if self.selections.count() == 1 {
 2931            self.add_selections_state = None;
 2932        }
 2933        self.select_next_state = None;
 2934        self.select_prev_state = None;
 2935        self.select_syntax_node_history.try_clear();
 2936        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2937        self.snippet_stack
 2938            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2939        self.take_rename(false, window, cx);
 2940
 2941        let newest_selection = self.selections.newest_anchor();
 2942        let new_cursor_position = newest_selection.head();
 2943        let selection_start = newest_selection.start;
 2944
 2945        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2946            self.push_to_nav_history(
 2947                *old_cursor_position,
 2948                Some(new_cursor_position.to_point(buffer)),
 2949                false,
 2950                effects.nav_history == Some(true),
 2951                cx,
 2952            );
 2953        }
 2954
 2955        if local {
 2956            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2957                if !self.registered_buffers.contains_key(&buffer_id) {
 2958                    if let Some(project) = self.project.as_ref() {
 2959                        project.update(cx, |project, cx| {
 2960                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2961                                return;
 2962                            };
 2963                            self.registered_buffers.insert(
 2964                                buffer_id,
 2965                                project.register_buffer_with_language_servers(&buffer, cx),
 2966                            );
 2967                        })
 2968                    }
 2969                }
 2970            }
 2971
 2972            let mut context_menu = self.context_menu.borrow_mut();
 2973            let completion_menu = match context_menu.as_ref() {
 2974                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2975                Some(CodeContextMenu::CodeActions(_)) => {
 2976                    *context_menu = None;
 2977                    None
 2978                }
 2979                None => None,
 2980            };
 2981            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2982            drop(context_menu);
 2983
 2984            if effects.completions {
 2985                if let Some(completion_position) = completion_position {
 2986                    let start_offset = selection_start.to_offset(buffer);
 2987                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2988                    let continue_showing = if position_matches {
 2989                        if self.snippet_stack.is_empty() {
 2990                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2991                        } else {
 2992                            // Snippet choices can be shown even when the cursor is in whitespace.
 2993                            // Dismissing the menu with actions like backspace is handled by
 2994                            // invalidation regions.
 2995                            true
 2996                        }
 2997                    } else {
 2998                        false
 2999                    };
 3000
 3001                    if continue_showing {
 3002                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3003                    } else {
 3004                        self.hide_context_menu(window, cx);
 3005                    }
 3006                }
 3007            }
 3008
 3009            hide_hover(self, cx);
 3010
 3011            if old_cursor_position.to_display_point(&display_map).row()
 3012                != new_cursor_position.to_display_point(&display_map).row()
 3013            {
 3014                self.available_code_actions.take();
 3015            }
 3016            self.refresh_code_actions(window, cx);
 3017            self.refresh_document_highlights(cx);
 3018            self.refresh_selected_text_highlights(false, window, cx);
 3019            refresh_matching_bracket_highlights(self, window, cx);
 3020            self.update_visible_inline_completion(window, cx);
 3021            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3022            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3023            self.inline_blame_popover.take();
 3024            if self.git_blame_inline_enabled {
 3025                self.start_inline_blame_timer(window, cx);
 3026            }
 3027        }
 3028
 3029        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3030        cx.emit(EditorEvent::SelectionsChanged { local });
 3031
 3032        let selections = &self.selections.disjoint;
 3033        if selections.len() == 1 {
 3034            cx.emit(SearchEvent::ActiveMatchChanged)
 3035        }
 3036        if local {
 3037            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3038                let inmemory_selections = selections
 3039                    .iter()
 3040                    .map(|s| {
 3041                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3042                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3043                    })
 3044                    .collect();
 3045                self.update_restoration_data(cx, |data| {
 3046                    data.selections = inmemory_selections;
 3047                });
 3048
 3049                if WorkspaceSettings::get(None, cx).restore_on_startup
 3050                    != RestoreOnStartupBehavior::None
 3051                {
 3052                    if let Some(workspace_id) =
 3053                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3054                    {
 3055                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3056                        let selections = selections.clone();
 3057                        let background_executor = cx.background_executor().clone();
 3058                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3059                        self.serialize_selections = cx.background_spawn(async move {
 3060                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3061                            let db_selections = selections
 3062                                .iter()
 3063                                .map(|selection| {
 3064                                    (
 3065                                        selection.start.to_offset(&snapshot),
 3066                                        selection.end.to_offset(&snapshot),
 3067                                    )
 3068                                })
 3069                                .collect();
 3070
 3071                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3072                                .await
 3073                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3074                                .log_err();
 3075                        });
 3076                    }
 3077                }
 3078            }
 3079        }
 3080
 3081        cx.notify();
 3082    }
 3083
 3084    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3085        use text::ToOffset as _;
 3086        use text::ToPoint as _;
 3087
 3088        if self.mode.is_minimap()
 3089            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3090        {
 3091            return;
 3092        }
 3093
 3094        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3095            return;
 3096        };
 3097
 3098        let snapshot = singleton.read(cx).snapshot();
 3099        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3100            let display_snapshot = display_map.snapshot(cx);
 3101
 3102            display_snapshot
 3103                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3104                .map(|fold| {
 3105                    fold.range.start.text_anchor.to_point(&snapshot)
 3106                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3107                })
 3108                .collect()
 3109        });
 3110        self.update_restoration_data(cx, |data| {
 3111            data.folds = inmemory_folds;
 3112        });
 3113
 3114        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3115            return;
 3116        };
 3117        let background_executor = cx.background_executor().clone();
 3118        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3119        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3120            display_map
 3121                .snapshot(cx)
 3122                .folds_in_range(0..snapshot.len())
 3123                .map(|fold| {
 3124                    (
 3125                        fold.range.start.text_anchor.to_offset(&snapshot),
 3126                        fold.range.end.text_anchor.to_offset(&snapshot),
 3127                    )
 3128                })
 3129                .collect()
 3130        });
 3131        self.serialize_folds = cx.background_spawn(async move {
 3132            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3133            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3134                .await
 3135                .with_context(|| {
 3136                    format!(
 3137                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3138                    )
 3139                })
 3140                .log_err();
 3141        });
 3142    }
 3143
 3144    pub fn sync_selections(
 3145        &mut self,
 3146        other: Entity<Editor>,
 3147        cx: &mut Context<Self>,
 3148    ) -> gpui::Subscription {
 3149        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3150        self.selections.change_with(cx, |selections| {
 3151            selections.select_anchors(other_selections);
 3152        });
 3153
 3154        let other_subscription =
 3155            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3156                EditorEvent::SelectionsChanged { local: true } => {
 3157                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3158                    if other_selections.is_empty() {
 3159                        return;
 3160                    }
 3161                    this.selections.change_with(cx, |selections| {
 3162                        selections.select_anchors(other_selections);
 3163                    });
 3164                }
 3165                _ => {}
 3166            });
 3167
 3168        let this_subscription =
 3169            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3170                EditorEvent::SelectionsChanged { local: true } => {
 3171                    let these_selections = this.selections.disjoint.to_vec();
 3172                    if these_selections.is_empty() {
 3173                        return;
 3174                    }
 3175                    other.update(cx, |other_editor, cx| {
 3176                        other_editor.selections.change_with(cx, |selections| {
 3177                            selections.select_anchors(these_selections);
 3178                        })
 3179                    });
 3180                }
 3181                _ => {}
 3182            });
 3183
 3184        Subscription::join(other_subscription, this_subscription)
 3185    }
 3186
 3187    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3188    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3189    /// effects of selection change occur at the end of the transaction.
 3190    pub fn change_selections<R>(
 3191        &mut self,
 3192        effects: SelectionEffects,
 3193        window: &mut Window,
 3194        cx: &mut Context<Self>,
 3195        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3196    ) -> R {
 3197        if let Some(state) = &mut self.deferred_selection_effects_state {
 3198            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3199            state.effects.completions = effects.completions;
 3200            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3201            let (changed, result) = self.selections.change_with(cx, change);
 3202            state.changed |= changed;
 3203            return result;
 3204        }
 3205        let mut state = DeferredSelectionEffectsState {
 3206            changed: false,
 3207            effects,
 3208            old_cursor_position: self.selections.newest_anchor().head(),
 3209            history_entry: SelectionHistoryEntry {
 3210                selections: self.selections.disjoint_anchors(),
 3211                select_next_state: self.select_next_state.clone(),
 3212                select_prev_state: self.select_prev_state.clone(),
 3213                add_selections_state: self.add_selections_state.clone(),
 3214            },
 3215        };
 3216        let (changed, result) = self.selections.change_with(cx, change);
 3217        state.changed = state.changed || changed;
 3218        if self.defer_selection_effects {
 3219            self.deferred_selection_effects_state = Some(state);
 3220        } else {
 3221            self.apply_selection_effects(state, window, cx);
 3222        }
 3223        result
 3224    }
 3225
 3226    /// Defers the effects of selection change, so that the effects of multiple calls to
 3227    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3228    /// to selection history and the state of popovers based on selection position aren't
 3229    /// erroneously updated.
 3230    pub fn with_selection_effects_deferred<R>(
 3231        &mut self,
 3232        window: &mut Window,
 3233        cx: &mut Context<Self>,
 3234        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3235    ) -> R {
 3236        let already_deferred = self.defer_selection_effects;
 3237        self.defer_selection_effects = true;
 3238        let result = update(self, window, cx);
 3239        if !already_deferred {
 3240            self.defer_selection_effects = false;
 3241            if let Some(state) = self.deferred_selection_effects_state.take() {
 3242                self.apply_selection_effects(state, window, cx);
 3243            }
 3244        }
 3245        result
 3246    }
 3247
 3248    fn apply_selection_effects(
 3249        &mut self,
 3250        state: DeferredSelectionEffectsState,
 3251        window: &mut Window,
 3252        cx: &mut Context<Self>,
 3253    ) {
 3254        if state.changed {
 3255            self.selection_history.push(state.history_entry);
 3256
 3257            if let Some(autoscroll) = state.effects.scroll {
 3258                self.request_autoscroll(autoscroll, cx);
 3259            }
 3260
 3261            let old_cursor_position = &state.old_cursor_position;
 3262
 3263            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3264
 3265            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3266                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3267            }
 3268        }
 3269    }
 3270
 3271    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3272    where
 3273        I: IntoIterator<Item = (Range<S>, T)>,
 3274        S: ToOffset,
 3275        T: Into<Arc<str>>,
 3276    {
 3277        if self.read_only(cx) {
 3278            return;
 3279        }
 3280
 3281        self.buffer
 3282            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3283    }
 3284
 3285    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3286    where
 3287        I: IntoIterator<Item = (Range<S>, T)>,
 3288        S: ToOffset,
 3289        T: Into<Arc<str>>,
 3290    {
 3291        if self.read_only(cx) {
 3292            return;
 3293        }
 3294
 3295        self.buffer.update(cx, |buffer, cx| {
 3296            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3297        });
 3298    }
 3299
 3300    pub fn edit_with_block_indent<I, S, T>(
 3301        &mut self,
 3302        edits: I,
 3303        original_indent_columns: Vec<Option<u32>>,
 3304        cx: &mut Context<Self>,
 3305    ) where
 3306        I: IntoIterator<Item = (Range<S>, T)>,
 3307        S: ToOffset,
 3308        T: Into<Arc<str>>,
 3309    {
 3310        if self.read_only(cx) {
 3311            return;
 3312        }
 3313
 3314        self.buffer.update(cx, |buffer, cx| {
 3315            buffer.edit(
 3316                edits,
 3317                Some(AutoindentMode::Block {
 3318                    original_indent_columns,
 3319                }),
 3320                cx,
 3321            )
 3322        });
 3323    }
 3324
 3325    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3326        self.hide_context_menu(window, cx);
 3327
 3328        match phase {
 3329            SelectPhase::Begin {
 3330                position,
 3331                add,
 3332                click_count,
 3333            } => self.begin_selection(position, add, click_count, window, cx),
 3334            SelectPhase::BeginColumnar {
 3335                position,
 3336                goal_column,
 3337                reset,
 3338                mode,
 3339            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3340            SelectPhase::Extend {
 3341                position,
 3342                click_count,
 3343            } => self.extend_selection(position, click_count, window, cx),
 3344            SelectPhase::Update {
 3345                position,
 3346                goal_column,
 3347                scroll_delta,
 3348            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3349            SelectPhase::End => self.end_selection(window, cx),
 3350        }
 3351    }
 3352
 3353    fn extend_selection(
 3354        &mut self,
 3355        position: DisplayPoint,
 3356        click_count: usize,
 3357        window: &mut Window,
 3358        cx: &mut Context<Self>,
 3359    ) {
 3360        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3361        let tail = self.selections.newest::<usize>(cx).tail();
 3362        self.begin_selection(position, false, click_count, window, cx);
 3363
 3364        let position = position.to_offset(&display_map, Bias::Left);
 3365        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3366
 3367        let mut pending_selection = self
 3368            .selections
 3369            .pending_anchor()
 3370            .expect("extend_selection not called with pending selection");
 3371        if position >= tail {
 3372            pending_selection.start = tail_anchor;
 3373        } else {
 3374            pending_selection.end = tail_anchor;
 3375            pending_selection.reversed = true;
 3376        }
 3377
 3378        let mut pending_mode = self.selections.pending_mode().unwrap();
 3379        match &mut pending_mode {
 3380            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3381            _ => {}
 3382        }
 3383
 3384        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3385            SelectionEffects::scroll(Autoscroll::fit())
 3386        } else {
 3387            SelectionEffects::no_scroll()
 3388        };
 3389
 3390        self.change_selections(effects, window, cx, |s| {
 3391            s.set_pending(pending_selection, pending_mode)
 3392        });
 3393    }
 3394
 3395    fn begin_selection(
 3396        &mut self,
 3397        position: DisplayPoint,
 3398        add: bool,
 3399        click_count: usize,
 3400        window: &mut Window,
 3401        cx: &mut Context<Self>,
 3402    ) {
 3403        if !self.focus_handle.is_focused(window) {
 3404            self.last_focused_descendant = None;
 3405            window.focus(&self.focus_handle);
 3406        }
 3407
 3408        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3409        let buffer = &display_map.buffer_snapshot;
 3410        let position = display_map.clip_point(position, Bias::Left);
 3411
 3412        let start;
 3413        let end;
 3414        let mode;
 3415        let mut auto_scroll;
 3416        match click_count {
 3417            1 => {
 3418                start = buffer.anchor_before(position.to_point(&display_map));
 3419                end = start;
 3420                mode = SelectMode::Character;
 3421                auto_scroll = true;
 3422            }
 3423            2 => {
 3424                let position = display_map
 3425                    .clip_point(position, Bias::Left)
 3426                    .to_offset(&display_map, Bias::Left);
 3427                let (range, _) = buffer.surrounding_word(position, false);
 3428                start = buffer.anchor_before(range.start);
 3429                end = buffer.anchor_before(range.end);
 3430                mode = SelectMode::Word(start..end);
 3431                auto_scroll = true;
 3432            }
 3433            3 => {
 3434                let position = display_map
 3435                    .clip_point(position, Bias::Left)
 3436                    .to_point(&display_map);
 3437                let line_start = display_map.prev_line_boundary(position).0;
 3438                let next_line_start = buffer.clip_point(
 3439                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3440                    Bias::Left,
 3441                );
 3442                start = buffer.anchor_before(line_start);
 3443                end = buffer.anchor_before(next_line_start);
 3444                mode = SelectMode::Line(start..end);
 3445                auto_scroll = true;
 3446            }
 3447            _ => {
 3448                start = buffer.anchor_before(0);
 3449                end = buffer.anchor_before(buffer.len());
 3450                mode = SelectMode::All;
 3451                auto_scroll = false;
 3452            }
 3453        }
 3454        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3455
 3456        let point_to_delete: Option<usize> = {
 3457            let selected_points: Vec<Selection<Point>> =
 3458                self.selections.disjoint_in_range(start..end, cx);
 3459
 3460            if !add || click_count > 1 {
 3461                None
 3462            } else if !selected_points.is_empty() {
 3463                Some(selected_points[0].id)
 3464            } else {
 3465                let clicked_point_already_selected =
 3466                    self.selections.disjoint.iter().find(|selection| {
 3467                        selection.start.to_point(buffer) == start.to_point(buffer)
 3468                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3469                    });
 3470
 3471                clicked_point_already_selected.map(|selection| selection.id)
 3472            }
 3473        };
 3474
 3475        let selections_count = self.selections.count();
 3476        let effects = if auto_scroll {
 3477            SelectionEffects::default()
 3478        } else {
 3479            SelectionEffects::no_scroll()
 3480        };
 3481
 3482        self.change_selections(effects, window, cx, |s| {
 3483            if let Some(point_to_delete) = point_to_delete {
 3484                s.delete(point_to_delete);
 3485
 3486                if selections_count == 1 {
 3487                    s.set_pending_anchor_range(start..end, mode);
 3488                }
 3489            } else {
 3490                if !add {
 3491                    s.clear_disjoint();
 3492                }
 3493
 3494                s.set_pending_anchor_range(start..end, mode);
 3495            }
 3496        });
 3497    }
 3498
 3499    fn begin_columnar_selection(
 3500        &mut self,
 3501        position: DisplayPoint,
 3502        goal_column: u32,
 3503        reset: bool,
 3504        mode: ColumnarMode,
 3505        window: &mut Window,
 3506        cx: &mut Context<Self>,
 3507    ) {
 3508        if !self.focus_handle.is_focused(window) {
 3509            self.last_focused_descendant = None;
 3510            window.focus(&self.focus_handle);
 3511        }
 3512
 3513        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3514
 3515        if reset {
 3516            let pointer_position = display_map
 3517                .buffer_snapshot
 3518                .anchor_before(position.to_point(&display_map));
 3519
 3520            self.change_selections(
 3521                SelectionEffects::scroll(Autoscroll::newest()),
 3522                window,
 3523                cx,
 3524                |s| {
 3525                    s.clear_disjoint();
 3526                    s.set_pending_anchor_range(
 3527                        pointer_position..pointer_position,
 3528                        SelectMode::Character,
 3529                    );
 3530                },
 3531            );
 3532        };
 3533
 3534        let tail = self.selections.newest::<Point>(cx).tail();
 3535        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3536        self.columnar_selection_state = match mode {
 3537            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3538                selection_tail: selection_anchor,
 3539                display_point: if reset {
 3540                    if position.column() != goal_column {
 3541                        Some(DisplayPoint::new(position.row(), goal_column))
 3542                    } else {
 3543                        None
 3544                    }
 3545                } else {
 3546                    None
 3547                },
 3548            }),
 3549            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3550                selection_tail: selection_anchor,
 3551            }),
 3552        };
 3553
 3554        if !reset {
 3555            self.select_columns(position, goal_column, &display_map, window, cx);
 3556        }
 3557    }
 3558
 3559    fn update_selection(
 3560        &mut self,
 3561        position: DisplayPoint,
 3562        goal_column: u32,
 3563        scroll_delta: gpui::Point<f32>,
 3564        window: &mut Window,
 3565        cx: &mut Context<Self>,
 3566    ) {
 3567        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3568
 3569        if self.columnar_selection_state.is_some() {
 3570            self.select_columns(position, goal_column, &display_map, window, cx);
 3571        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3572            let buffer = &display_map.buffer_snapshot;
 3573            let head;
 3574            let tail;
 3575            let mode = self.selections.pending_mode().unwrap();
 3576            match &mode {
 3577                SelectMode::Character => {
 3578                    head = position.to_point(&display_map);
 3579                    tail = pending.tail().to_point(buffer);
 3580                }
 3581                SelectMode::Word(original_range) => {
 3582                    let offset = display_map
 3583                        .clip_point(position, Bias::Left)
 3584                        .to_offset(&display_map, Bias::Left);
 3585                    let original_range = original_range.to_offset(buffer);
 3586
 3587                    let head_offset = if buffer.is_inside_word(offset, false)
 3588                        || original_range.contains(&offset)
 3589                    {
 3590                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3591                        if word_range.start < original_range.start {
 3592                            word_range.start
 3593                        } else {
 3594                            word_range.end
 3595                        }
 3596                    } else {
 3597                        offset
 3598                    };
 3599
 3600                    head = head_offset.to_point(buffer);
 3601                    if head_offset <= original_range.start {
 3602                        tail = original_range.end.to_point(buffer);
 3603                    } else {
 3604                        tail = original_range.start.to_point(buffer);
 3605                    }
 3606                }
 3607                SelectMode::Line(original_range) => {
 3608                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3609
 3610                    let position = display_map
 3611                        .clip_point(position, Bias::Left)
 3612                        .to_point(&display_map);
 3613                    let line_start = display_map.prev_line_boundary(position).0;
 3614                    let next_line_start = buffer.clip_point(
 3615                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3616                        Bias::Left,
 3617                    );
 3618
 3619                    if line_start < original_range.start {
 3620                        head = line_start
 3621                    } else {
 3622                        head = next_line_start
 3623                    }
 3624
 3625                    if head <= original_range.start {
 3626                        tail = original_range.end;
 3627                    } else {
 3628                        tail = original_range.start;
 3629                    }
 3630                }
 3631                SelectMode::All => {
 3632                    return;
 3633                }
 3634            };
 3635
 3636            if head < tail {
 3637                pending.start = buffer.anchor_before(head);
 3638                pending.end = buffer.anchor_before(tail);
 3639                pending.reversed = true;
 3640            } else {
 3641                pending.start = buffer.anchor_before(tail);
 3642                pending.end = buffer.anchor_before(head);
 3643                pending.reversed = false;
 3644            }
 3645
 3646            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3647                s.set_pending(pending, mode);
 3648            });
 3649        } else {
 3650            log::error!("update_selection dispatched with no pending selection");
 3651            return;
 3652        }
 3653
 3654        self.apply_scroll_delta(scroll_delta, window, cx);
 3655        cx.notify();
 3656    }
 3657
 3658    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3659        self.columnar_selection_state.take();
 3660        if self.selections.pending_anchor().is_some() {
 3661            let selections = self.selections.all::<usize>(cx);
 3662            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3663                s.select(selections);
 3664                s.clear_pending();
 3665            });
 3666        }
 3667    }
 3668
 3669    fn select_columns(
 3670        &mut self,
 3671        head: DisplayPoint,
 3672        goal_column: u32,
 3673        display_map: &DisplaySnapshot,
 3674        window: &mut Window,
 3675        cx: &mut Context<Self>,
 3676    ) {
 3677        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3678            return;
 3679        };
 3680
 3681        let tail = match columnar_state {
 3682            ColumnarSelectionState::FromMouse {
 3683                selection_tail,
 3684                display_point,
 3685            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3686            ColumnarSelectionState::FromSelection { selection_tail } => {
 3687                selection_tail.to_display_point(&display_map)
 3688            }
 3689        };
 3690
 3691        let start_row = cmp::min(tail.row(), head.row());
 3692        let end_row = cmp::max(tail.row(), head.row());
 3693        let start_column = cmp::min(tail.column(), goal_column);
 3694        let end_column = cmp::max(tail.column(), goal_column);
 3695        let reversed = start_column < tail.column();
 3696
 3697        let selection_ranges = (start_row.0..=end_row.0)
 3698            .map(DisplayRow)
 3699            .filter_map(|row| {
 3700                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3701                    || start_column <= display_map.line_len(row))
 3702                    && !display_map.is_block_line(row)
 3703                {
 3704                    let start = display_map
 3705                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3706                        .to_point(display_map);
 3707                    let end = display_map
 3708                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3709                        .to_point(display_map);
 3710                    if reversed {
 3711                        Some(end..start)
 3712                    } else {
 3713                        Some(start..end)
 3714                    }
 3715                } else {
 3716                    None
 3717                }
 3718            })
 3719            .collect::<Vec<_>>();
 3720
 3721        let ranges = match columnar_state {
 3722            ColumnarSelectionState::FromMouse { .. } => {
 3723                let mut non_empty_ranges = selection_ranges
 3724                    .iter()
 3725                    .filter(|selection_range| selection_range.start != selection_range.end)
 3726                    .peekable();
 3727                if non_empty_ranges.peek().is_some() {
 3728                    non_empty_ranges.cloned().collect()
 3729                } else {
 3730                    selection_ranges
 3731                }
 3732            }
 3733            _ => selection_ranges,
 3734        };
 3735
 3736        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3737            s.select_ranges(ranges);
 3738        });
 3739        cx.notify();
 3740    }
 3741
 3742    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3743        self.selections
 3744            .all_adjusted(cx)
 3745            .iter()
 3746            .any(|selection| !selection.is_empty())
 3747    }
 3748
 3749    pub fn has_pending_nonempty_selection(&self) -> bool {
 3750        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3751            Some(Selection { start, end, .. }) => start != end,
 3752            None => false,
 3753        };
 3754
 3755        pending_nonempty_selection
 3756            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3757    }
 3758
 3759    pub fn has_pending_selection(&self) -> bool {
 3760        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3761    }
 3762
 3763    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3764        self.selection_mark_mode = false;
 3765        self.selection_drag_state = SelectionDragState::None;
 3766
 3767        if self.clear_expanded_diff_hunks(cx) {
 3768            cx.notify();
 3769            return;
 3770        }
 3771        if self.dismiss_menus_and_popups(true, window, cx) {
 3772            return;
 3773        }
 3774
 3775        if self.mode.is_full()
 3776            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3777        {
 3778            return;
 3779        }
 3780
 3781        cx.propagate();
 3782    }
 3783
 3784    pub fn dismiss_menus_and_popups(
 3785        &mut self,
 3786        is_user_requested: bool,
 3787        window: &mut Window,
 3788        cx: &mut Context<Self>,
 3789    ) -> bool {
 3790        if self.take_rename(false, window, cx).is_some() {
 3791            return true;
 3792        }
 3793
 3794        if hide_hover(self, cx) {
 3795            return true;
 3796        }
 3797
 3798        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3799            return true;
 3800        }
 3801
 3802        if self.hide_context_menu(window, cx).is_some() {
 3803            return true;
 3804        }
 3805
 3806        if self.mouse_context_menu.take().is_some() {
 3807            return true;
 3808        }
 3809
 3810        if is_user_requested && self.discard_inline_completion(true, cx) {
 3811            return true;
 3812        }
 3813
 3814        if self.snippet_stack.pop().is_some() {
 3815            return true;
 3816        }
 3817
 3818        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3819            self.dismiss_diagnostics(cx);
 3820            return true;
 3821        }
 3822
 3823        false
 3824    }
 3825
 3826    fn linked_editing_ranges_for(
 3827        &self,
 3828        selection: Range<text::Anchor>,
 3829        cx: &App,
 3830    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3831        if self.linked_edit_ranges.is_empty() {
 3832            return None;
 3833        }
 3834        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3835            selection.end.buffer_id.and_then(|end_buffer_id| {
 3836                if selection.start.buffer_id != Some(end_buffer_id) {
 3837                    return None;
 3838                }
 3839                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3840                let snapshot = buffer.read(cx).snapshot();
 3841                self.linked_edit_ranges
 3842                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3843                    .map(|ranges| (ranges, snapshot, buffer))
 3844            })?;
 3845        use text::ToOffset as TO;
 3846        // find offset from the start of current range to current cursor position
 3847        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3848
 3849        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3850        let start_difference = start_offset - start_byte_offset;
 3851        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3852        let end_difference = end_offset - start_byte_offset;
 3853        // Current range has associated linked ranges.
 3854        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3855        for range in linked_ranges.iter() {
 3856            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3857            let end_offset = start_offset + end_difference;
 3858            let start_offset = start_offset + start_difference;
 3859            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3860                continue;
 3861            }
 3862            if self.selections.disjoint_anchor_ranges().any(|s| {
 3863                if s.start.buffer_id != selection.start.buffer_id
 3864                    || s.end.buffer_id != selection.end.buffer_id
 3865                {
 3866                    return false;
 3867                }
 3868                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3869                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3870            }) {
 3871                continue;
 3872            }
 3873            let start = buffer_snapshot.anchor_after(start_offset);
 3874            let end = buffer_snapshot.anchor_after(end_offset);
 3875            linked_edits
 3876                .entry(buffer.clone())
 3877                .or_default()
 3878                .push(start..end);
 3879        }
 3880        Some(linked_edits)
 3881    }
 3882
 3883    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3884        let text: Arc<str> = text.into();
 3885
 3886        if self.read_only(cx) {
 3887            return;
 3888        }
 3889
 3890        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3891
 3892        let selections = self.selections.all_adjusted(cx);
 3893        let mut bracket_inserted = false;
 3894        let mut edits = Vec::new();
 3895        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3896        let mut new_selections = Vec::with_capacity(selections.len());
 3897        let mut new_autoclose_regions = Vec::new();
 3898        let snapshot = self.buffer.read(cx).read(cx);
 3899        let mut clear_linked_edit_ranges = false;
 3900
 3901        for (selection, autoclose_region) in
 3902            self.selections_with_autoclose_regions(selections, &snapshot)
 3903        {
 3904            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3905                // Determine if the inserted text matches the opening or closing
 3906                // bracket of any of this language's bracket pairs.
 3907                let mut bracket_pair = None;
 3908                let mut is_bracket_pair_start = false;
 3909                let mut is_bracket_pair_end = false;
 3910                if !text.is_empty() {
 3911                    let mut bracket_pair_matching_end = None;
 3912                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3913                    //  and they are removing the character that triggered IME popup.
 3914                    for (pair, enabled) in scope.brackets() {
 3915                        if !pair.close && !pair.surround {
 3916                            continue;
 3917                        }
 3918
 3919                        if enabled && pair.start.ends_with(text.as_ref()) {
 3920                            let prefix_len = pair.start.len() - text.len();
 3921                            let preceding_text_matches_prefix = prefix_len == 0
 3922                                || (selection.start.column >= (prefix_len as u32)
 3923                                    && snapshot.contains_str_at(
 3924                                        Point::new(
 3925                                            selection.start.row,
 3926                                            selection.start.column - (prefix_len as u32),
 3927                                        ),
 3928                                        &pair.start[..prefix_len],
 3929                                    ));
 3930                            if preceding_text_matches_prefix {
 3931                                bracket_pair = Some(pair.clone());
 3932                                is_bracket_pair_start = true;
 3933                                break;
 3934                            }
 3935                        }
 3936                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3937                        {
 3938                            // take first bracket pair matching end, but don't break in case a later bracket
 3939                            // pair matches start
 3940                            bracket_pair_matching_end = Some(pair.clone());
 3941                        }
 3942                    }
 3943                    if let Some(end) = bracket_pair_matching_end
 3944                        && bracket_pair.is_none()
 3945                    {
 3946                        bracket_pair = Some(end);
 3947                        is_bracket_pair_end = true;
 3948                    }
 3949                }
 3950
 3951                if let Some(bracket_pair) = bracket_pair {
 3952                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3953                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3954                    let auto_surround =
 3955                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3956                    if selection.is_empty() {
 3957                        if is_bracket_pair_start {
 3958                            // If the inserted text is a suffix of an opening bracket and the
 3959                            // selection is preceded by the rest of the opening bracket, then
 3960                            // insert the closing bracket.
 3961                            let following_text_allows_autoclose = snapshot
 3962                                .chars_at(selection.start)
 3963                                .next()
 3964                                .map_or(true, |c| scope.should_autoclose_before(c));
 3965
 3966                            let preceding_text_allows_autoclose = selection.start.column == 0
 3967                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3968                                    true,
 3969                                    |c| {
 3970                                        bracket_pair.start != bracket_pair.end
 3971                                            || !snapshot
 3972                                                .char_classifier_at(selection.start)
 3973                                                .is_word(c)
 3974                                    },
 3975                                );
 3976
 3977                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3978                                && bracket_pair.start.len() == 1
 3979                            {
 3980                                let target = bracket_pair.start.chars().next().unwrap();
 3981                                let current_line_count = snapshot
 3982                                    .reversed_chars_at(selection.start)
 3983                                    .take_while(|&c| c != '\n')
 3984                                    .filter(|&c| c == target)
 3985                                    .count();
 3986                                current_line_count % 2 == 1
 3987                            } else {
 3988                                false
 3989                            };
 3990
 3991                            if autoclose
 3992                                && bracket_pair.close
 3993                                && following_text_allows_autoclose
 3994                                && preceding_text_allows_autoclose
 3995                                && !is_closing_quote
 3996                            {
 3997                                let anchor = snapshot.anchor_before(selection.end);
 3998                                new_selections.push((selection.map(|_| anchor), text.len()));
 3999                                new_autoclose_regions.push((
 4000                                    anchor,
 4001                                    text.len(),
 4002                                    selection.id,
 4003                                    bracket_pair.clone(),
 4004                                ));
 4005                                edits.push((
 4006                                    selection.range(),
 4007                                    format!("{}{}", text, bracket_pair.end).into(),
 4008                                ));
 4009                                bracket_inserted = true;
 4010                                continue;
 4011                            }
 4012                        }
 4013
 4014                        if let Some(region) = autoclose_region {
 4015                            // If the selection is followed by an auto-inserted closing bracket,
 4016                            // then don't insert that closing bracket again; just move the selection
 4017                            // past the closing bracket.
 4018                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4019                                && text.as_ref() == region.pair.end.as_str();
 4020                            if should_skip {
 4021                                let anchor = snapshot.anchor_after(selection.end);
 4022                                new_selections
 4023                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4024                                continue;
 4025                            }
 4026                        }
 4027
 4028                        let always_treat_brackets_as_autoclosed = snapshot
 4029                            .language_settings_at(selection.start, cx)
 4030                            .always_treat_brackets_as_autoclosed;
 4031                        if always_treat_brackets_as_autoclosed
 4032                            && is_bracket_pair_end
 4033                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4034                        {
 4035                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4036                            // and the inserted text is a closing bracket and the selection is followed
 4037                            // by the closing bracket then move the selection past the closing bracket.
 4038                            let anchor = snapshot.anchor_after(selection.end);
 4039                            new_selections.push((selection.map(|_| anchor), text.len()));
 4040                            continue;
 4041                        }
 4042                    }
 4043                    // If an opening bracket is 1 character long and is typed while
 4044                    // text is selected, then surround that text with the bracket pair.
 4045                    else if auto_surround
 4046                        && bracket_pair.surround
 4047                        && is_bracket_pair_start
 4048                        && bracket_pair.start.chars().count() == 1
 4049                    {
 4050                        edits.push((selection.start..selection.start, text.clone()));
 4051                        edits.push((
 4052                            selection.end..selection.end,
 4053                            bracket_pair.end.as_str().into(),
 4054                        ));
 4055                        bracket_inserted = true;
 4056                        new_selections.push((
 4057                            Selection {
 4058                                id: selection.id,
 4059                                start: snapshot.anchor_after(selection.start),
 4060                                end: snapshot.anchor_before(selection.end),
 4061                                reversed: selection.reversed,
 4062                                goal: selection.goal,
 4063                            },
 4064                            0,
 4065                        ));
 4066                        continue;
 4067                    }
 4068                }
 4069            }
 4070
 4071            if self.auto_replace_emoji_shortcode
 4072                && selection.is_empty()
 4073                && text.as_ref().ends_with(':')
 4074            {
 4075                if let Some(possible_emoji_short_code) =
 4076                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4077                {
 4078                    if !possible_emoji_short_code.is_empty() {
 4079                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4080                            let emoji_shortcode_start = Point::new(
 4081                                selection.start.row,
 4082                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4083                            );
 4084
 4085                            // Remove shortcode from buffer
 4086                            edits.push((
 4087                                emoji_shortcode_start..selection.start,
 4088                                "".to_string().into(),
 4089                            ));
 4090                            new_selections.push((
 4091                                Selection {
 4092                                    id: selection.id,
 4093                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4094                                    end: snapshot.anchor_before(selection.start),
 4095                                    reversed: selection.reversed,
 4096                                    goal: selection.goal,
 4097                                },
 4098                                0,
 4099                            ));
 4100
 4101                            // Insert emoji
 4102                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4103                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4104                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4105
 4106                            continue;
 4107                        }
 4108                    }
 4109                }
 4110            }
 4111
 4112            // If not handling any auto-close operation, then just replace the selected
 4113            // text with the given input and move the selection to the end of the
 4114            // newly inserted text.
 4115            let anchor = snapshot.anchor_after(selection.end);
 4116            if !self.linked_edit_ranges.is_empty() {
 4117                let start_anchor = snapshot.anchor_before(selection.start);
 4118
 4119                let is_word_char = text.chars().next().map_or(true, |char| {
 4120                    let classifier = snapshot
 4121                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4122                        .ignore_punctuation(true);
 4123                    classifier.is_word(char)
 4124                });
 4125
 4126                if is_word_char {
 4127                    if let Some(ranges) = self
 4128                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4129                    {
 4130                        for (buffer, edits) in ranges {
 4131                            linked_edits
 4132                                .entry(buffer.clone())
 4133                                .or_default()
 4134                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4135                        }
 4136                    }
 4137                } else {
 4138                    clear_linked_edit_ranges = true;
 4139                }
 4140            }
 4141
 4142            new_selections.push((selection.map(|_| anchor), 0));
 4143            edits.push((selection.start..selection.end, text.clone()));
 4144        }
 4145
 4146        drop(snapshot);
 4147
 4148        self.transact(window, cx, |this, window, cx| {
 4149            if clear_linked_edit_ranges {
 4150                this.linked_edit_ranges.clear();
 4151            }
 4152            let initial_buffer_versions =
 4153                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4154
 4155            this.buffer.update(cx, |buffer, cx| {
 4156                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4157            });
 4158            for (buffer, edits) in linked_edits {
 4159                buffer.update(cx, |buffer, cx| {
 4160                    let snapshot = buffer.snapshot();
 4161                    let edits = edits
 4162                        .into_iter()
 4163                        .map(|(range, text)| {
 4164                            use text::ToPoint as TP;
 4165                            let end_point = TP::to_point(&range.end, &snapshot);
 4166                            let start_point = TP::to_point(&range.start, &snapshot);
 4167                            (start_point..end_point, text)
 4168                        })
 4169                        .sorted_by_key(|(range, _)| range.start);
 4170                    buffer.edit(edits, None, cx);
 4171                })
 4172            }
 4173            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4174            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4175            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4176            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4177                .zip(new_selection_deltas)
 4178                .map(|(selection, delta)| Selection {
 4179                    id: selection.id,
 4180                    start: selection.start + delta,
 4181                    end: selection.end + delta,
 4182                    reversed: selection.reversed,
 4183                    goal: SelectionGoal::None,
 4184                })
 4185                .collect::<Vec<_>>();
 4186
 4187            let mut i = 0;
 4188            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4189                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4190                let start = map.buffer_snapshot.anchor_before(position);
 4191                let end = map.buffer_snapshot.anchor_after(position);
 4192                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4193                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4194                        Ordering::Less => i += 1,
 4195                        Ordering::Greater => break,
 4196                        Ordering::Equal => {
 4197                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4198                                Ordering::Less => i += 1,
 4199                                Ordering::Equal => break,
 4200                                Ordering::Greater => break,
 4201                            }
 4202                        }
 4203                    }
 4204                }
 4205                this.autoclose_regions.insert(
 4206                    i,
 4207                    AutocloseRegion {
 4208                        selection_id,
 4209                        range: start..end,
 4210                        pair,
 4211                    },
 4212                );
 4213            }
 4214
 4215            let had_active_inline_completion = this.has_active_inline_completion();
 4216            this.change_selections(
 4217                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4218                window,
 4219                cx,
 4220                |s| s.select(new_selections),
 4221            );
 4222
 4223            if !bracket_inserted {
 4224                if let Some(on_type_format_task) =
 4225                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4226                {
 4227                    on_type_format_task.detach_and_log_err(cx);
 4228                }
 4229            }
 4230
 4231            let editor_settings = EditorSettings::get_global(cx);
 4232            if bracket_inserted
 4233                && (editor_settings.auto_signature_help
 4234                    || editor_settings.show_signature_help_after_edits)
 4235            {
 4236                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4237            }
 4238
 4239            let trigger_in_words =
 4240                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4241            if this.hard_wrap.is_some() {
 4242                let latest: Range<Point> = this.selections.newest(cx).range();
 4243                if latest.is_empty()
 4244                    && this
 4245                        .buffer()
 4246                        .read(cx)
 4247                        .snapshot(cx)
 4248                        .line_len(MultiBufferRow(latest.start.row))
 4249                        == latest.start.column
 4250                {
 4251                    this.rewrap_impl(
 4252                        RewrapOptions {
 4253                            override_language_settings: true,
 4254                            preserve_existing_whitespace: true,
 4255                        },
 4256                        cx,
 4257                    )
 4258                }
 4259            }
 4260            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4261            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4262            this.refresh_inline_completion(true, false, window, cx);
 4263            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4264        });
 4265    }
 4266
 4267    fn find_possible_emoji_shortcode_at_position(
 4268        snapshot: &MultiBufferSnapshot,
 4269        position: Point,
 4270    ) -> Option<String> {
 4271        let mut chars = Vec::new();
 4272        let mut found_colon = false;
 4273        for char in snapshot.reversed_chars_at(position).take(100) {
 4274            // Found a possible emoji shortcode in the middle of the buffer
 4275            if found_colon {
 4276                if char.is_whitespace() {
 4277                    chars.reverse();
 4278                    return Some(chars.iter().collect());
 4279                }
 4280                // If the previous character is not a whitespace, we are in the middle of a word
 4281                // and we only want to complete the shortcode if the word is made up of other emojis
 4282                let mut containing_word = String::new();
 4283                for ch in snapshot
 4284                    .reversed_chars_at(position)
 4285                    .skip(chars.len() + 1)
 4286                    .take(100)
 4287                {
 4288                    if ch.is_whitespace() {
 4289                        break;
 4290                    }
 4291                    containing_word.push(ch);
 4292                }
 4293                let containing_word = containing_word.chars().rev().collect::<String>();
 4294                if util::word_consists_of_emojis(containing_word.as_str()) {
 4295                    chars.reverse();
 4296                    return Some(chars.iter().collect());
 4297                }
 4298            }
 4299
 4300            if char.is_whitespace() || !char.is_ascii() {
 4301                return None;
 4302            }
 4303            if char == ':' {
 4304                found_colon = true;
 4305            } else {
 4306                chars.push(char);
 4307            }
 4308        }
 4309        // Found a possible emoji shortcode at the beginning of the buffer
 4310        chars.reverse();
 4311        Some(chars.iter().collect())
 4312    }
 4313
 4314    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4316        self.transact(window, cx, |this, window, cx| {
 4317            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4318                let selections = this.selections.all::<usize>(cx);
 4319                let multi_buffer = this.buffer.read(cx);
 4320                let buffer = multi_buffer.snapshot(cx);
 4321                selections
 4322                    .iter()
 4323                    .map(|selection| {
 4324                        let start_point = selection.start.to_point(&buffer);
 4325                        let mut existing_indent =
 4326                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4327                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4328                        let start = selection.start;
 4329                        let end = selection.end;
 4330                        let selection_is_empty = start == end;
 4331                        let language_scope = buffer.language_scope_at(start);
 4332                        let (
 4333                            comment_delimiter,
 4334                            doc_delimiter,
 4335                            insert_extra_newline,
 4336                            indent_on_newline,
 4337                            indent_on_extra_newline,
 4338                        ) = if let Some(language) = &language_scope {
 4339                            let mut insert_extra_newline =
 4340                                insert_extra_newline_brackets(&buffer, start..end, language)
 4341                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4342
 4343                            // Comment extension on newline is allowed only for cursor selections
 4344                            let comment_delimiter = maybe!({
 4345                                if !selection_is_empty {
 4346                                    return None;
 4347                                }
 4348
 4349                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4350                                    return None;
 4351                                }
 4352
 4353                                let delimiters = language.line_comment_prefixes();
 4354                                let max_len_of_delimiter =
 4355                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4356                                let (snapshot, range) =
 4357                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4358
 4359                                let num_of_whitespaces = snapshot
 4360                                    .chars_for_range(range.clone())
 4361                                    .take_while(|c| c.is_whitespace())
 4362                                    .count();
 4363                                let comment_candidate = snapshot
 4364                                    .chars_for_range(range)
 4365                                    .skip(num_of_whitespaces)
 4366                                    .take(max_len_of_delimiter)
 4367                                    .collect::<String>();
 4368                                let (delimiter, trimmed_len) = delimiters
 4369                                    .iter()
 4370                                    .filter_map(|delimiter| {
 4371                                        let prefix = delimiter.trim_end();
 4372                                        if comment_candidate.starts_with(prefix) {
 4373                                            Some((delimiter, prefix.len()))
 4374                                        } else {
 4375                                            None
 4376                                        }
 4377                                    })
 4378                                    .max_by_key(|(_, len)| *len)?;
 4379
 4380                                let cursor_is_placed_after_comment_marker =
 4381                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4382                                if cursor_is_placed_after_comment_marker {
 4383                                    Some(delimiter.clone())
 4384                                } else {
 4385                                    None
 4386                                }
 4387                            });
 4388
 4389                            let mut indent_on_newline = IndentSize::spaces(0);
 4390                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4391
 4392                            let doc_delimiter = maybe!({
 4393                                if !selection_is_empty {
 4394                                    return None;
 4395                                }
 4396
 4397                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4398                                    return None;
 4399                                }
 4400
 4401                                let DocumentationConfig {
 4402                                    start: start_tag,
 4403                                    end: end_tag,
 4404                                    prefix: delimiter,
 4405                                    tab_size: len,
 4406                                } = language.documentation()?;
 4407
 4408                                let is_within_block_comment = buffer
 4409                                    .language_scope_at(start_point)
 4410                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4411                                if !is_within_block_comment {
 4412                                    return None;
 4413                                }
 4414
 4415                                let (snapshot, range) =
 4416                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4417
 4418                                let num_of_whitespaces = snapshot
 4419                                    .chars_for_range(range.clone())
 4420                                    .take_while(|c| c.is_whitespace())
 4421                                    .count();
 4422
 4423                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4424                                let column = start_point.column;
 4425                                let cursor_is_after_start_tag = {
 4426                                    let start_tag_len = start_tag.len();
 4427                                    let start_tag_line = snapshot
 4428                                        .chars_for_range(range.clone())
 4429                                        .skip(num_of_whitespaces)
 4430                                        .take(start_tag_len)
 4431                                        .collect::<String>();
 4432                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4433                                        num_of_whitespaces + start_tag_len <= column as usize
 4434                                    } else {
 4435                                        false
 4436                                    }
 4437                                };
 4438
 4439                                let cursor_is_after_delimiter = {
 4440                                    let delimiter_trim = delimiter.trim_end();
 4441                                    let delimiter_line = snapshot
 4442                                        .chars_for_range(range.clone())
 4443                                        .skip(num_of_whitespaces)
 4444                                        .take(delimiter_trim.len())
 4445                                        .collect::<String>();
 4446                                    if delimiter_line.starts_with(delimiter_trim) {
 4447                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4448                                    } else {
 4449                                        false
 4450                                    }
 4451                                };
 4452
 4453                                let cursor_is_before_end_tag_if_exists = {
 4454                                    let mut char_position = 0u32;
 4455                                    let mut end_tag_offset = None;
 4456
 4457                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4458                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4459                                            let chars_before_match =
 4460                                                chunk[..byte_pos].chars().count() as u32;
 4461                                            end_tag_offset =
 4462                                                Some(char_position + chars_before_match);
 4463                                            break 'outer;
 4464                                        }
 4465                                        char_position += chunk.chars().count() as u32;
 4466                                    }
 4467
 4468                                    if let Some(end_tag_offset) = end_tag_offset {
 4469                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4470                                        if cursor_is_after_start_tag {
 4471                                            if cursor_is_before_end_tag {
 4472                                                insert_extra_newline = true;
 4473                                            }
 4474                                            let cursor_is_at_start_of_end_tag =
 4475                                                column == end_tag_offset;
 4476                                            if cursor_is_at_start_of_end_tag {
 4477                                                indent_on_extra_newline.len = (*len).into();
 4478                                            }
 4479                                        }
 4480                                        cursor_is_before_end_tag
 4481                                    } else {
 4482                                        true
 4483                                    }
 4484                                };
 4485
 4486                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4487                                    && cursor_is_before_end_tag_if_exists
 4488                                {
 4489                                    if cursor_is_after_start_tag {
 4490                                        indent_on_newline.len = (*len).into();
 4491                                    }
 4492                                    Some(delimiter.clone())
 4493                                } else {
 4494                                    None
 4495                                }
 4496                            });
 4497
 4498                            (
 4499                                comment_delimiter,
 4500                                doc_delimiter,
 4501                                insert_extra_newline,
 4502                                indent_on_newline,
 4503                                indent_on_extra_newline,
 4504                            )
 4505                        } else {
 4506                            (
 4507                                None,
 4508                                None,
 4509                                false,
 4510                                IndentSize::default(),
 4511                                IndentSize::default(),
 4512                            )
 4513                        };
 4514
 4515                        let prevent_auto_indent = doc_delimiter.is_some();
 4516                        let delimiter = comment_delimiter.or(doc_delimiter);
 4517
 4518                        let capacity_for_delimiter =
 4519                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4520                        let mut new_text = String::with_capacity(
 4521                            1 + capacity_for_delimiter
 4522                                + existing_indent.len as usize
 4523                                + indent_on_newline.len as usize
 4524                                + indent_on_extra_newline.len as usize,
 4525                        );
 4526                        new_text.push('\n');
 4527                        new_text.extend(existing_indent.chars());
 4528                        new_text.extend(indent_on_newline.chars());
 4529
 4530                        if let Some(delimiter) = &delimiter {
 4531                            new_text.push_str(delimiter);
 4532                        }
 4533
 4534                        if insert_extra_newline {
 4535                            new_text.push('\n');
 4536                            new_text.extend(existing_indent.chars());
 4537                            new_text.extend(indent_on_extra_newline.chars());
 4538                        }
 4539
 4540                        let anchor = buffer.anchor_after(end);
 4541                        let new_selection = selection.map(|_| anchor);
 4542                        (
 4543                            ((start..end, new_text), prevent_auto_indent),
 4544                            (insert_extra_newline, new_selection),
 4545                        )
 4546                    })
 4547                    .unzip()
 4548            };
 4549
 4550            let mut auto_indent_edits = Vec::new();
 4551            let mut edits = Vec::new();
 4552            for (edit, prevent_auto_indent) in edits_with_flags {
 4553                if prevent_auto_indent {
 4554                    edits.push(edit);
 4555                } else {
 4556                    auto_indent_edits.push(edit);
 4557                }
 4558            }
 4559            if !edits.is_empty() {
 4560                this.edit(edits, cx);
 4561            }
 4562            if !auto_indent_edits.is_empty() {
 4563                this.edit_with_autoindent(auto_indent_edits, cx);
 4564            }
 4565
 4566            let buffer = this.buffer.read(cx).snapshot(cx);
 4567            let new_selections = selection_info
 4568                .into_iter()
 4569                .map(|(extra_newline_inserted, new_selection)| {
 4570                    let mut cursor = new_selection.end.to_point(&buffer);
 4571                    if extra_newline_inserted {
 4572                        cursor.row -= 1;
 4573                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4574                    }
 4575                    new_selection.map(|_| cursor)
 4576                })
 4577                .collect();
 4578
 4579            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4580            this.refresh_inline_completion(true, false, window, cx);
 4581        });
 4582    }
 4583
 4584    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4585        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4586
 4587        let buffer = self.buffer.read(cx);
 4588        let snapshot = buffer.snapshot(cx);
 4589
 4590        let mut edits = Vec::new();
 4591        let mut rows = Vec::new();
 4592
 4593        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4594            let cursor = selection.head();
 4595            let row = cursor.row;
 4596
 4597            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4598
 4599            let newline = "\n".to_string();
 4600            edits.push((start_of_line..start_of_line, newline));
 4601
 4602            rows.push(row + rows_inserted as u32);
 4603        }
 4604
 4605        self.transact(window, cx, |editor, window, cx| {
 4606            editor.edit(edits, cx);
 4607
 4608            editor.change_selections(Default::default(), window, cx, |s| {
 4609                let mut index = 0;
 4610                s.move_cursors_with(|map, _, _| {
 4611                    let row = rows[index];
 4612                    index += 1;
 4613
 4614                    let point = Point::new(row, 0);
 4615                    let boundary = map.next_line_boundary(point).1;
 4616                    let clipped = map.clip_point(boundary, Bias::Left);
 4617
 4618                    (clipped, SelectionGoal::None)
 4619                });
 4620            });
 4621
 4622            let mut indent_edits = Vec::new();
 4623            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4624            for row in rows {
 4625                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4626                for (row, indent) in indents {
 4627                    if indent.len == 0 {
 4628                        continue;
 4629                    }
 4630
 4631                    let text = match indent.kind {
 4632                        IndentKind::Space => " ".repeat(indent.len as usize),
 4633                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4634                    };
 4635                    let point = Point::new(row.0, 0);
 4636                    indent_edits.push((point..point, text));
 4637                }
 4638            }
 4639            editor.edit(indent_edits, cx);
 4640        });
 4641    }
 4642
 4643    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4644        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4645
 4646        let buffer = self.buffer.read(cx);
 4647        let snapshot = buffer.snapshot(cx);
 4648
 4649        let mut edits = Vec::new();
 4650        let mut rows = Vec::new();
 4651        let mut rows_inserted = 0;
 4652
 4653        for selection in self.selections.all_adjusted(cx) {
 4654            let cursor = selection.head();
 4655            let row = cursor.row;
 4656
 4657            let point = Point::new(row + 1, 0);
 4658            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4659
 4660            let newline = "\n".to_string();
 4661            edits.push((start_of_line..start_of_line, newline));
 4662
 4663            rows_inserted += 1;
 4664            rows.push(row + rows_inserted);
 4665        }
 4666
 4667        self.transact(window, cx, |editor, window, cx| {
 4668            editor.edit(edits, cx);
 4669
 4670            editor.change_selections(Default::default(), window, cx, |s| {
 4671                let mut index = 0;
 4672                s.move_cursors_with(|map, _, _| {
 4673                    let row = rows[index];
 4674                    index += 1;
 4675
 4676                    let point = Point::new(row, 0);
 4677                    let boundary = map.next_line_boundary(point).1;
 4678                    let clipped = map.clip_point(boundary, Bias::Left);
 4679
 4680                    (clipped, SelectionGoal::None)
 4681                });
 4682            });
 4683
 4684            let mut indent_edits = Vec::new();
 4685            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4686            for row in rows {
 4687                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4688                for (row, indent) in indents {
 4689                    if indent.len == 0 {
 4690                        continue;
 4691                    }
 4692
 4693                    let text = match indent.kind {
 4694                        IndentKind::Space => " ".repeat(indent.len as usize),
 4695                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4696                    };
 4697                    let point = Point::new(row.0, 0);
 4698                    indent_edits.push((point..point, text));
 4699                }
 4700            }
 4701            editor.edit(indent_edits, cx);
 4702        });
 4703    }
 4704
 4705    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4706        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4707            original_indent_columns: Vec::new(),
 4708        });
 4709        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4710    }
 4711
 4712    fn insert_with_autoindent_mode(
 4713        &mut self,
 4714        text: &str,
 4715        autoindent_mode: Option<AutoindentMode>,
 4716        window: &mut Window,
 4717        cx: &mut Context<Self>,
 4718    ) {
 4719        if self.read_only(cx) {
 4720            return;
 4721        }
 4722
 4723        let text: Arc<str> = text.into();
 4724        self.transact(window, cx, |this, window, cx| {
 4725            let old_selections = this.selections.all_adjusted(cx);
 4726            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4727                let anchors = {
 4728                    let snapshot = buffer.read(cx);
 4729                    old_selections
 4730                        .iter()
 4731                        .map(|s| {
 4732                            let anchor = snapshot.anchor_after(s.head());
 4733                            s.map(|_| anchor)
 4734                        })
 4735                        .collect::<Vec<_>>()
 4736                };
 4737                buffer.edit(
 4738                    old_selections
 4739                        .iter()
 4740                        .map(|s| (s.start..s.end, text.clone())),
 4741                    autoindent_mode,
 4742                    cx,
 4743                );
 4744                anchors
 4745            });
 4746
 4747            this.change_selections(Default::default(), window, cx, |s| {
 4748                s.select_anchors(selection_anchors);
 4749            });
 4750
 4751            cx.notify();
 4752        });
 4753    }
 4754
 4755    fn trigger_completion_on_input(
 4756        &mut self,
 4757        text: &str,
 4758        trigger_in_words: bool,
 4759        window: &mut Window,
 4760        cx: &mut Context<Self>,
 4761    ) {
 4762        let completions_source = self
 4763            .context_menu
 4764            .borrow()
 4765            .as_ref()
 4766            .and_then(|menu| match menu {
 4767                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4768                CodeContextMenu::CodeActions(_) => None,
 4769            });
 4770
 4771        match completions_source {
 4772            Some(CompletionsMenuSource::Words) => {
 4773                self.show_word_completions(&ShowWordCompletions, window, cx)
 4774            }
 4775            Some(CompletionsMenuSource::Normal)
 4776            | Some(CompletionsMenuSource::SnippetChoices)
 4777            | None
 4778                if self.is_completion_trigger(
 4779                    text,
 4780                    trigger_in_words,
 4781                    completions_source.is_some(),
 4782                    cx,
 4783                ) =>
 4784            {
 4785                self.show_completions(
 4786                    &ShowCompletions {
 4787                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4788                    },
 4789                    window,
 4790                    cx,
 4791                )
 4792            }
 4793            _ => {
 4794                self.hide_context_menu(window, cx);
 4795            }
 4796        }
 4797    }
 4798
 4799    fn is_completion_trigger(
 4800        &self,
 4801        text: &str,
 4802        trigger_in_words: bool,
 4803        menu_is_open: bool,
 4804        cx: &mut Context<Self>,
 4805    ) -> bool {
 4806        let position = self.selections.newest_anchor().head();
 4807        let multibuffer = self.buffer.read(cx);
 4808        let Some(buffer) = position
 4809            .buffer_id
 4810            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4811        else {
 4812            return false;
 4813        };
 4814
 4815        if let Some(completion_provider) = &self.completion_provider {
 4816            completion_provider.is_completion_trigger(
 4817                &buffer,
 4818                position.text_anchor,
 4819                text,
 4820                trigger_in_words,
 4821                menu_is_open,
 4822                cx,
 4823            )
 4824        } else {
 4825            false
 4826        }
 4827    }
 4828
 4829    /// If any empty selections is touching the start of its innermost containing autoclose
 4830    /// region, expand it to select the brackets.
 4831    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4832        let selections = self.selections.all::<usize>(cx);
 4833        let buffer = self.buffer.read(cx).read(cx);
 4834        let new_selections = self
 4835            .selections_with_autoclose_regions(selections, &buffer)
 4836            .map(|(mut selection, region)| {
 4837                if !selection.is_empty() {
 4838                    return selection;
 4839                }
 4840
 4841                if let Some(region) = region {
 4842                    let mut range = region.range.to_offset(&buffer);
 4843                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4844                        range.start -= region.pair.start.len();
 4845                        if buffer.contains_str_at(range.start, &region.pair.start)
 4846                            && buffer.contains_str_at(range.end, &region.pair.end)
 4847                        {
 4848                            range.end += region.pair.end.len();
 4849                            selection.start = range.start;
 4850                            selection.end = range.end;
 4851
 4852                            return selection;
 4853                        }
 4854                    }
 4855                }
 4856
 4857                let always_treat_brackets_as_autoclosed = buffer
 4858                    .language_settings_at(selection.start, cx)
 4859                    .always_treat_brackets_as_autoclosed;
 4860
 4861                if !always_treat_brackets_as_autoclosed {
 4862                    return selection;
 4863                }
 4864
 4865                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4866                    for (pair, enabled) in scope.brackets() {
 4867                        if !enabled || !pair.close {
 4868                            continue;
 4869                        }
 4870
 4871                        if buffer.contains_str_at(selection.start, &pair.end) {
 4872                            let pair_start_len = pair.start.len();
 4873                            if buffer.contains_str_at(
 4874                                selection.start.saturating_sub(pair_start_len),
 4875                                &pair.start,
 4876                            ) {
 4877                                selection.start -= pair_start_len;
 4878                                selection.end += pair.end.len();
 4879
 4880                                return selection;
 4881                            }
 4882                        }
 4883                    }
 4884                }
 4885
 4886                selection
 4887            })
 4888            .collect();
 4889
 4890        drop(buffer);
 4891        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4892            selections.select(new_selections)
 4893        });
 4894    }
 4895
 4896    /// Iterate the given selections, and for each one, find the smallest surrounding
 4897    /// autoclose region. This uses the ordering of the selections and the autoclose
 4898    /// regions to avoid repeated comparisons.
 4899    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4900        &'a self,
 4901        selections: impl IntoIterator<Item = Selection<D>>,
 4902        buffer: &'a MultiBufferSnapshot,
 4903    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4904        let mut i = 0;
 4905        let mut regions = self.autoclose_regions.as_slice();
 4906        selections.into_iter().map(move |selection| {
 4907            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4908
 4909            let mut enclosing = None;
 4910            while let Some(pair_state) = regions.get(i) {
 4911                if pair_state.range.end.to_offset(buffer) < range.start {
 4912                    regions = &regions[i + 1..];
 4913                    i = 0;
 4914                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4915                    break;
 4916                } else {
 4917                    if pair_state.selection_id == selection.id {
 4918                        enclosing = Some(pair_state);
 4919                    }
 4920                    i += 1;
 4921                }
 4922            }
 4923
 4924            (selection, enclosing)
 4925        })
 4926    }
 4927
 4928    /// Remove any autoclose regions that no longer contain their selection.
 4929    fn invalidate_autoclose_regions(
 4930        &mut self,
 4931        mut selections: &[Selection<Anchor>],
 4932        buffer: &MultiBufferSnapshot,
 4933    ) {
 4934        self.autoclose_regions.retain(|state| {
 4935            let mut i = 0;
 4936            while let Some(selection) = selections.get(i) {
 4937                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4938                    selections = &selections[1..];
 4939                    continue;
 4940                }
 4941                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4942                    break;
 4943                }
 4944                if selection.id == state.selection_id {
 4945                    return true;
 4946                } else {
 4947                    i += 1;
 4948                }
 4949            }
 4950            false
 4951        });
 4952    }
 4953
 4954    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4955        let offset = position.to_offset(buffer);
 4956        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4957        if offset > word_range.start && kind == Some(CharKind::Word) {
 4958            Some(
 4959                buffer
 4960                    .text_for_range(word_range.start..offset)
 4961                    .collect::<String>(),
 4962            )
 4963        } else {
 4964            None
 4965        }
 4966    }
 4967
 4968    pub fn toggle_inline_values(
 4969        &mut self,
 4970        _: &ToggleInlineValues,
 4971        _: &mut Window,
 4972        cx: &mut Context<Self>,
 4973    ) {
 4974        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4975
 4976        self.refresh_inline_values(cx);
 4977    }
 4978
 4979    pub fn toggle_inlay_hints(
 4980        &mut self,
 4981        _: &ToggleInlayHints,
 4982        _: &mut Window,
 4983        cx: &mut Context<Self>,
 4984    ) {
 4985        self.refresh_inlay_hints(
 4986            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4987            cx,
 4988        );
 4989    }
 4990
 4991    pub fn inlay_hints_enabled(&self) -> bool {
 4992        self.inlay_hint_cache.enabled
 4993    }
 4994
 4995    pub fn inline_values_enabled(&self) -> bool {
 4996        self.inline_value_cache.enabled
 4997    }
 4998
 4999    #[cfg(any(test, feature = "test-support"))]
 5000    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5001        self.display_map
 5002            .read(cx)
 5003            .current_inlays()
 5004            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5005            .cloned()
 5006            .collect()
 5007    }
 5008
 5009    #[cfg(any(test, feature = "test-support"))]
 5010    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5011        self.display_map
 5012            .read(cx)
 5013            .current_inlays()
 5014            .cloned()
 5015            .collect()
 5016    }
 5017
 5018    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5019        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5020            return;
 5021        }
 5022
 5023        let reason_description = reason.description();
 5024        let ignore_debounce = matches!(
 5025            reason,
 5026            InlayHintRefreshReason::SettingsChange(_)
 5027                | InlayHintRefreshReason::Toggle(_)
 5028                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5029                | InlayHintRefreshReason::ModifiersChanged(_)
 5030        );
 5031        let (invalidate_cache, required_languages) = match reason {
 5032            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5033                match self.inlay_hint_cache.modifiers_override(enabled) {
 5034                    Some(enabled) => {
 5035                        if enabled {
 5036                            (InvalidationStrategy::RefreshRequested, None)
 5037                        } else {
 5038                            self.splice_inlays(
 5039                                &self
 5040                                    .visible_inlay_hints(cx)
 5041                                    .iter()
 5042                                    .map(|inlay| inlay.id)
 5043                                    .collect::<Vec<InlayId>>(),
 5044                                Vec::new(),
 5045                                cx,
 5046                            );
 5047                            return;
 5048                        }
 5049                    }
 5050                    None => return,
 5051                }
 5052            }
 5053            InlayHintRefreshReason::Toggle(enabled) => {
 5054                if self.inlay_hint_cache.toggle(enabled) {
 5055                    if enabled {
 5056                        (InvalidationStrategy::RefreshRequested, None)
 5057                    } else {
 5058                        self.splice_inlays(
 5059                            &self
 5060                                .visible_inlay_hints(cx)
 5061                                .iter()
 5062                                .map(|inlay| inlay.id)
 5063                                .collect::<Vec<InlayId>>(),
 5064                            Vec::new(),
 5065                            cx,
 5066                        );
 5067                        return;
 5068                    }
 5069                } else {
 5070                    return;
 5071                }
 5072            }
 5073            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5074                match self.inlay_hint_cache.update_settings(
 5075                    &self.buffer,
 5076                    new_settings,
 5077                    self.visible_inlay_hints(cx),
 5078                    cx,
 5079                ) {
 5080                    ControlFlow::Break(Some(InlaySplice {
 5081                        to_remove,
 5082                        to_insert,
 5083                    })) => {
 5084                        self.splice_inlays(&to_remove, to_insert, cx);
 5085                        return;
 5086                    }
 5087                    ControlFlow::Break(None) => return,
 5088                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5089                }
 5090            }
 5091            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5092                if let Some(InlaySplice {
 5093                    to_remove,
 5094                    to_insert,
 5095                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5096                {
 5097                    self.splice_inlays(&to_remove, to_insert, cx);
 5098                }
 5099                self.display_map.update(cx, |display_map, _| {
 5100                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5101                });
 5102                return;
 5103            }
 5104            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5105            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5106                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5107            }
 5108            InlayHintRefreshReason::RefreshRequested => {
 5109                (InvalidationStrategy::RefreshRequested, None)
 5110            }
 5111        };
 5112
 5113        if let Some(InlaySplice {
 5114            to_remove,
 5115            to_insert,
 5116        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5117            reason_description,
 5118            self.visible_excerpts(required_languages.as_ref(), cx),
 5119            invalidate_cache,
 5120            ignore_debounce,
 5121            cx,
 5122        ) {
 5123            self.splice_inlays(&to_remove, to_insert, cx);
 5124        }
 5125    }
 5126
 5127    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5128        self.display_map
 5129            .read(cx)
 5130            .current_inlays()
 5131            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5132            .cloned()
 5133            .collect()
 5134    }
 5135
 5136    pub fn visible_excerpts(
 5137        &self,
 5138        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5139        cx: &mut Context<Editor>,
 5140    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5141        let Some(project) = self.project.as_ref() else {
 5142            return HashMap::default();
 5143        };
 5144        let project = project.read(cx);
 5145        let multi_buffer = self.buffer().read(cx);
 5146        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5147        let multi_buffer_visible_start = self
 5148            .scroll_manager
 5149            .anchor()
 5150            .anchor
 5151            .to_point(&multi_buffer_snapshot);
 5152        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5153            multi_buffer_visible_start
 5154                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5155            Bias::Left,
 5156        );
 5157        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5158        multi_buffer_snapshot
 5159            .range_to_buffer_ranges(multi_buffer_visible_range)
 5160            .into_iter()
 5161            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5162            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5163                let buffer_file = project::File::from_dyn(buffer.file())?;
 5164                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5165                let worktree_entry = buffer_worktree
 5166                    .read(cx)
 5167                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5168                if worktree_entry.is_ignored {
 5169                    return None;
 5170                }
 5171
 5172                let language = buffer.language()?;
 5173                if let Some(restrict_to_languages) = restrict_to_languages {
 5174                    if !restrict_to_languages.contains(language) {
 5175                        return None;
 5176                    }
 5177                }
 5178                Some((
 5179                    excerpt_id,
 5180                    (
 5181                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5182                        buffer.version().clone(),
 5183                        excerpt_visible_range,
 5184                    ),
 5185                ))
 5186            })
 5187            .collect()
 5188    }
 5189
 5190    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5191        TextLayoutDetails {
 5192            text_system: window.text_system().clone(),
 5193            editor_style: self.style.clone().unwrap(),
 5194            rem_size: window.rem_size(),
 5195            scroll_anchor: self.scroll_manager.anchor(),
 5196            visible_rows: self.visible_line_count(),
 5197            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5198        }
 5199    }
 5200
 5201    pub fn splice_inlays(
 5202        &self,
 5203        to_remove: &[InlayId],
 5204        to_insert: Vec<Inlay>,
 5205        cx: &mut Context<Self>,
 5206    ) {
 5207        self.display_map.update(cx, |display_map, cx| {
 5208            display_map.splice_inlays(to_remove, to_insert, cx)
 5209        });
 5210        cx.notify();
 5211    }
 5212
 5213    fn trigger_on_type_formatting(
 5214        &self,
 5215        input: String,
 5216        window: &mut Window,
 5217        cx: &mut Context<Self>,
 5218    ) -> Option<Task<Result<()>>> {
 5219        if input.len() != 1 {
 5220            return None;
 5221        }
 5222
 5223        let project = self.project.as_ref()?;
 5224        let position = self.selections.newest_anchor().head();
 5225        let (buffer, buffer_position) = self
 5226            .buffer
 5227            .read(cx)
 5228            .text_anchor_for_position(position, cx)?;
 5229
 5230        let settings = language_settings::language_settings(
 5231            buffer
 5232                .read(cx)
 5233                .language_at(buffer_position)
 5234                .map(|l| l.name()),
 5235            buffer.read(cx).file(),
 5236            cx,
 5237        );
 5238        if !settings.use_on_type_format {
 5239            return None;
 5240        }
 5241
 5242        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5243        // hence we do LSP request & edit on host side only — add formats to host's history.
 5244        let push_to_lsp_host_history = true;
 5245        // If this is not the host, append its history with new edits.
 5246        let push_to_client_history = project.read(cx).is_via_collab();
 5247
 5248        let on_type_formatting = project.update(cx, |project, cx| {
 5249            project.on_type_format(
 5250                buffer.clone(),
 5251                buffer_position,
 5252                input,
 5253                push_to_lsp_host_history,
 5254                cx,
 5255            )
 5256        });
 5257        Some(cx.spawn_in(window, async move |editor, cx| {
 5258            if let Some(transaction) = on_type_formatting.await? {
 5259                if push_to_client_history {
 5260                    buffer
 5261                        .update(cx, |buffer, _| {
 5262                            buffer.push_transaction(transaction, Instant::now());
 5263                            buffer.finalize_last_transaction();
 5264                        })
 5265                        .ok();
 5266                }
 5267                editor.update(cx, |editor, cx| {
 5268                    editor.refresh_document_highlights(cx);
 5269                })?;
 5270            }
 5271            Ok(())
 5272        }))
 5273    }
 5274
 5275    pub fn show_word_completions(
 5276        &mut self,
 5277        _: &ShowWordCompletions,
 5278        window: &mut Window,
 5279        cx: &mut Context<Self>,
 5280    ) {
 5281        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5282    }
 5283
 5284    pub fn show_completions(
 5285        &mut self,
 5286        options: &ShowCompletions,
 5287        window: &mut Window,
 5288        cx: &mut Context<Self>,
 5289    ) {
 5290        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5291    }
 5292
 5293    fn open_or_update_completions_menu(
 5294        &mut self,
 5295        requested_source: Option<CompletionsMenuSource>,
 5296        trigger: Option<&str>,
 5297        window: &mut Window,
 5298        cx: &mut Context<Self>,
 5299    ) {
 5300        if self.pending_rename.is_some() {
 5301            return;
 5302        }
 5303
 5304        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5305
 5306        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5307        // inserted and selected. To handle that case, the start of the selection is used so that
 5308        // the menu starts with all choices.
 5309        let position = self
 5310            .selections
 5311            .newest_anchor()
 5312            .start
 5313            .bias_right(&multibuffer_snapshot);
 5314        if position.diff_base_anchor.is_some() {
 5315            return;
 5316        }
 5317        let (buffer, buffer_position) =
 5318            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5319                output
 5320            } else {
 5321                return;
 5322            };
 5323        let buffer_snapshot = buffer.read(cx).snapshot();
 5324
 5325        let query: Option<Arc<String>> =
 5326            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5327
 5328        drop(multibuffer_snapshot);
 5329
 5330        let provider = match requested_source {
 5331            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5332            Some(CompletionsMenuSource::Words) => None,
 5333            Some(CompletionsMenuSource::SnippetChoices) => {
 5334                log::error!("bug: SnippetChoices requested_source is not handled");
 5335                None
 5336            }
 5337        };
 5338
 5339        let sort_completions = provider
 5340            .as_ref()
 5341            .map_or(false, |provider| provider.sort_completions());
 5342
 5343        let filter_completions = provider
 5344            .as_ref()
 5345            .map_or(true, |provider| provider.filter_completions());
 5346
 5347        let trigger_kind = match trigger {
 5348            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5349                CompletionTriggerKind::TRIGGER_CHARACTER
 5350            }
 5351            _ => CompletionTriggerKind::INVOKED,
 5352        };
 5353        let completion_context = CompletionContext {
 5354            trigger_character: trigger.and_then(|trigger| {
 5355                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5356                    Some(String::from(trigger))
 5357                } else {
 5358                    None
 5359                }
 5360            }),
 5361            trigger_kind,
 5362        };
 5363
 5364        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5365        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5366        // involve trigger chars, so this is skipped in that case.
 5367        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5368        {
 5369            let menu_is_open = matches!(
 5370                self.context_menu.borrow().as_ref(),
 5371                Some(CodeContextMenu::Completions(_))
 5372            );
 5373            if menu_is_open {
 5374                self.hide_context_menu(window, cx);
 5375            }
 5376        }
 5377
 5378        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5379            if filter_completions {
 5380                menu.filter(query.clone(), provider.clone(), window, cx);
 5381            }
 5382            // When `is_incomplete` is false, no need to re-query completions when the current query
 5383            // is a suffix of the initial query.
 5384            if !menu.is_incomplete {
 5385                // If the new query is a suffix of the old query (typing more characters) and
 5386                // the previous result was complete, the existing completions can be filtered.
 5387                //
 5388                // Note that this is always true for snippet completions.
 5389                let query_matches = match (&menu.initial_query, &query) {
 5390                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5391                    (None, _) => true,
 5392                    _ => false,
 5393                };
 5394                if query_matches {
 5395                    let position_matches = if menu.initial_position == position {
 5396                        true
 5397                    } else {
 5398                        let snapshot = self.buffer.read(cx).read(cx);
 5399                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5400                    };
 5401                    if position_matches {
 5402                        return;
 5403                    }
 5404                }
 5405            }
 5406        };
 5407
 5408        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5409            buffer_snapshot.surrounding_word(buffer_position)
 5410        {
 5411            let word_to_exclude = buffer_snapshot
 5412                .text_for_range(word_range.clone())
 5413                .collect::<String>();
 5414            (
 5415                buffer_snapshot.anchor_before(word_range.start)
 5416                    ..buffer_snapshot.anchor_after(buffer_position),
 5417                Some(word_to_exclude),
 5418            )
 5419        } else {
 5420            (buffer_position..buffer_position, None)
 5421        };
 5422
 5423        let language = buffer_snapshot
 5424            .language_at(buffer_position)
 5425            .map(|language| language.name());
 5426
 5427        let completion_settings =
 5428            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5429
 5430        let show_completion_documentation = buffer_snapshot
 5431            .settings_at(buffer_position, cx)
 5432            .show_completion_documentation;
 5433
 5434        // The document can be large, so stay in reasonable bounds when searching for words,
 5435        // otherwise completion pop-up might be slow to appear.
 5436        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5437        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5438        let min_word_search = buffer_snapshot.clip_point(
 5439            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5440            Bias::Left,
 5441        );
 5442        let max_word_search = buffer_snapshot.clip_point(
 5443            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5444            Bias::Right,
 5445        );
 5446        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5447            ..buffer_snapshot.point_to_offset(max_word_search);
 5448
 5449        let skip_digits = query
 5450            .as_ref()
 5451            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5452
 5453        let (mut words, provider_responses) = match &provider {
 5454            Some(provider) => {
 5455                let provider_responses = provider.completions(
 5456                    position.excerpt_id,
 5457                    &buffer,
 5458                    buffer_position,
 5459                    completion_context,
 5460                    window,
 5461                    cx,
 5462                );
 5463
 5464                let words = match completion_settings.words {
 5465                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5466                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5467                        .background_spawn(async move {
 5468                            buffer_snapshot.words_in_range(WordsQuery {
 5469                                fuzzy_contents: None,
 5470                                range: word_search_range,
 5471                                skip_digits,
 5472                            })
 5473                        }),
 5474                };
 5475
 5476                (words, provider_responses)
 5477            }
 5478            None => (
 5479                cx.background_spawn(async move {
 5480                    buffer_snapshot.words_in_range(WordsQuery {
 5481                        fuzzy_contents: None,
 5482                        range: word_search_range,
 5483                        skip_digits,
 5484                    })
 5485                }),
 5486                Task::ready(Ok(Vec::new())),
 5487            ),
 5488        };
 5489
 5490        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5491
 5492        let id = post_inc(&mut self.next_completion_id);
 5493        let task = cx.spawn_in(window, async move |editor, cx| {
 5494            let Ok(()) = editor.update(cx, |this, _| {
 5495                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5496            }) else {
 5497                return;
 5498            };
 5499
 5500            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5501            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5502            let mut completions = Vec::new();
 5503            let mut is_incomplete = false;
 5504            if let Some(provider_responses) = provider_responses.await.log_err() {
 5505                if !provider_responses.is_empty() {
 5506                    for response in provider_responses {
 5507                        completions.extend(response.completions);
 5508                        is_incomplete = is_incomplete || response.is_incomplete;
 5509                    }
 5510                    if completion_settings.words == WordsCompletionMode::Fallback {
 5511                        words = Task::ready(BTreeMap::default());
 5512                    }
 5513                }
 5514            }
 5515
 5516            let mut words = words.await;
 5517            if let Some(word_to_exclude) = &word_to_exclude {
 5518                words.remove(word_to_exclude);
 5519            }
 5520            for lsp_completion in &completions {
 5521                words.remove(&lsp_completion.new_text);
 5522            }
 5523            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5524                replace_range: word_replace_range.clone(),
 5525                new_text: word.clone(),
 5526                label: CodeLabel::plain(word, None),
 5527                icon_path: None,
 5528                documentation: None,
 5529                source: CompletionSource::BufferWord {
 5530                    word_range,
 5531                    resolved: false,
 5532                },
 5533                insert_text_mode: Some(InsertTextMode::AS_IS),
 5534                confirm: None,
 5535            }));
 5536
 5537            let menu = if completions.is_empty() {
 5538                None
 5539            } else {
 5540                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5541                    let languages = editor
 5542                        .workspace
 5543                        .as_ref()
 5544                        .and_then(|(workspace, _)| workspace.upgrade())
 5545                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5546                    let menu = CompletionsMenu::new(
 5547                        id,
 5548                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5549                        sort_completions,
 5550                        show_completion_documentation,
 5551                        position,
 5552                        query.clone(),
 5553                        is_incomplete,
 5554                        buffer.clone(),
 5555                        completions.into(),
 5556                        snippet_sort_order,
 5557                        languages,
 5558                        language,
 5559                        cx,
 5560                    );
 5561
 5562                    let query = if filter_completions { query } else { None };
 5563                    let matches_task = if let Some(query) = query {
 5564                        menu.do_async_filtering(query, cx)
 5565                    } else {
 5566                        Task::ready(menu.unfiltered_matches())
 5567                    };
 5568                    (menu, matches_task)
 5569                }) else {
 5570                    return;
 5571                };
 5572
 5573                let matches = matches_task.await;
 5574
 5575                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5576                    // Newer menu already set, so exit.
 5577                    match editor.context_menu.borrow().as_ref() {
 5578                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5579                            if prev_menu.id > id {
 5580                                return;
 5581                            }
 5582                        }
 5583                        _ => {}
 5584                    };
 5585
 5586                    // Only valid to take prev_menu because it the new menu is immediately set
 5587                    // below, or the menu is hidden.
 5588                    match editor.context_menu.borrow_mut().take() {
 5589                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5590                            let position_matches =
 5591                                if prev_menu.initial_position == menu.initial_position {
 5592                                    true
 5593                                } else {
 5594                                    let snapshot = editor.buffer.read(cx).read(cx);
 5595                                    prev_menu.initial_position.to_offset(&snapshot)
 5596                                        == menu.initial_position.to_offset(&snapshot)
 5597                                };
 5598                            if position_matches {
 5599                                // Preserve markdown cache before `set_filter_results` because it will
 5600                                // try to populate the documentation cache.
 5601                                menu.preserve_markdown_cache(prev_menu);
 5602                            }
 5603                        }
 5604                        _ => {}
 5605                    };
 5606
 5607                    menu.set_filter_results(matches, provider, window, cx);
 5608                }) else {
 5609                    return;
 5610                };
 5611
 5612                menu.visible().then_some(menu)
 5613            };
 5614
 5615            editor
 5616                .update_in(cx, |editor, window, cx| {
 5617                    if editor.focus_handle.is_focused(window) {
 5618                        if let Some(menu) = menu {
 5619                            *editor.context_menu.borrow_mut() =
 5620                                Some(CodeContextMenu::Completions(menu));
 5621
 5622                            crate::hover_popover::hide_hover(editor, cx);
 5623                            if editor.show_edit_predictions_in_menu() {
 5624                                editor.update_visible_inline_completion(window, cx);
 5625                            } else {
 5626                                editor.discard_inline_completion(false, cx);
 5627                            }
 5628
 5629                            cx.notify();
 5630                            return;
 5631                        }
 5632                    }
 5633
 5634                    if editor.completion_tasks.len() <= 1 {
 5635                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5636                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5637                        // If it was already hidden and we don't show inline completions in the menu, we should
 5638                        // also show the inline-completion when available.
 5639                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5640                            editor.update_visible_inline_completion(window, cx);
 5641                        }
 5642                    }
 5643                })
 5644                .ok();
 5645        });
 5646
 5647        self.completion_tasks.push((id, task));
 5648    }
 5649
 5650    #[cfg(feature = "test-support")]
 5651    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5652        let menu = self.context_menu.borrow();
 5653        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5654            let completions = menu.completions.borrow();
 5655            Some(completions.to_vec())
 5656        } else {
 5657            None
 5658        }
 5659    }
 5660
 5661    pub fn with_completions_menu_matching_id<R>(
 5662        &self,
 5663        id: CompletionId,
 5664        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5665    ) -> R {
 5666        let mut context_menu = self.context_menu.borrow_mut();
 5667        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5668            return f(None);
 5669        };
 5670        if completions_menu.id != id {
 5671            return f(None);
 5672        }
 5673        f(Some(completions_menu))
 5674    }
 5675
 5676    pub fn confirm_completion(
 5677        &mut self,
 5678        action: &ConfirmCompletion,
 5679        window: &mut Window,
 5680        cx: &mut Context<Self>,
 5681    ) -> Option<Task<Result<()>>> {
 5682        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5683        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5684    }
 5685
 5686    pub fn confirm_completion_insert(
 5687        &mut self,
 5688        _: &ConfirmCompletionInsert,
 5689        window: &mut Window,
 5690        cx: &mut Context<Self>,
 5691    ) -> Option<Task<Result<()>>> {
 5692        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5693        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5694    }
 5695
 5696    pub fn confirm_completion_replace(
 5697        &mut self,
 5698        _: &ConfirmCompletionReplace,
 5699        window: &mut Window,
 5700        cx: &mut Context<Self>,
 5701    ) -> Option<Task<Result<()>>> {
 5702        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5703        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5704    }
 5705
 5706    pub fn compose_completion(
 5707        &mut self,
 5708        action: &ComposeCompletion,
 5709        window: &mut Window,
 5710        cx: &mut Context<Self>,
 5711    ) -> Option<Task<Result<()>>> {
 5712        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5713        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5714    }
 5715
 5716    fn do_completion(
 5717        &mut self,
 5718        item_ix: Option<usize>,
 5719        intent: CompletionIntent,
 5720        window: &mut Window,
 5721        cx: &mut Context<Editor>,
 5722    ) -> Option<Task<Result<()>>> {
 5723        use language::ToOffset as _;
 5724
 5725        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5726        else {
 5727            return None;
 5728        };
 5729
 5730        let candidate_id = {
 5731            let entries = completions_menu.entries.borrow();
 5732            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5733            if self.show_edit_predictions_in_menu() {
 5734                self.discard_inline_completion(true, cx);
 5735            }
 5736            mat.candidate_id
 5737        };
 5738
 5739        let completion = completions_menu
 5740            .completions
 5741            .borrow()
 5742            .get(candidate_id)?
 5743            .clone();
 5744        cx.stop_propagation();
 5745
 5746        let buffer_handle = completions_menu.buffer.clone();
 5747
 5748        let CompletionEdit {
 5749            new_text,
 5750            snippet,
 5751            replace_range,
 5752        } = process_completion_for_edit(
 5753            &completion,
 5754            intent,
 5755            &buffer_handle,
 5756            &completions_menu.initial_position.text_anchor,
 5757            cx,
 5758        );
 5759
 5760        let buffer = buffer_handle.read(cx);
 5761        let snapshot = self.buffer.read(cx).snapshot(cx);
 5762        let newest_anchor = self.selections.newest_anchor();
 5763        let replace_range_multibuffer = {
 5764            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5765            let multibuffer_anchor = snapshot
 5766                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5767                .unwrap()
 5768                ..snapshot
 5769                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5770                    .unwrap();
 5771            multibuffer_anchor.start.to_offset(&snapshot)
 5772                ..multibuffer_anchor.end.to_offset(&snapshot)
 5773        };
 5774        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5775            return None;
 5776        }
 5777
 5778        let old_text = buffer
 5779            .text_for_range(replace_range.clone())
 5780            .collect::<String>();
 5781        let lookbehind = newest_anchor
 5782            .start
 5783            .text_anchor
 5784            .to_offset(buffer)
 5785            .saturating_sub(replace_range.start);
 5786        let lookahead = replace_range
 5787            .end
 5788            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5789        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5790        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5791
 5792        let selections = self.selections.all::<usize>(cx);
 5793        let mut ranges = Vec::new();
 5794        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5795
 5796        for selection in &selections {
 5797            let range = if selection.id == newest_anchor.id {
 5798                replace_range_multibuffer.clone()
 5799            } else {
 5800                let mut range = selection.range();
 5801
 5802                // if prefix is present, don't duplicate it
 5803                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5804                    range.start = range.start.saturating_sub(lookbehind);
 5805
 5806                    // if suffix is also present, mimic the newest cursor and replace it
 5807                    if selection.id != newest_anchor.id
 5808                        && snapshot.contains_str_at(range.end, suffix)
 5809                    {
 5810                        range.end += lookahead;
 5811                    }
 5812                }
 5813                range
 5814            };
 5815
 5816            ranges.push(range.clone());
 5817
 5818            if !self.linked_edit_ranges.is_empty() {
 5819                let start_anchor = snapshot.anchor_before(range.start);
 5820                let end_anchor = snapshot.anchor_after(range.end);
 5821                if let Some(ranges) = self
 5822                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5823                {
 5824                    for (buffer, edits) in ranges {
 5825                        linked_edits
 5826                            .entry(buffer.clone())
 5827                            .or_default()
 5828                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5829                    }
 5830                }
 5831            }
 5832        }
 5833
 5834        let common_prefix_len = old_text
 5835            .chars()
 5836            .zip(new_text.chars())
 5837            .take_while(|(a, b)| a == b)
 5838            .map(|(a, _)| a.len_utf8())
 5839            .sum::<usize>();
 5840
 5841        cx.emit(EditorEvent::InputHandled {
 5842            utf16_range_to_replace: None,
 5843            text: new_text[common_prefix_len..].into(),
 5844        });
 5845
 5846        self.transact(window, cx, |this, window, cx| {
 5847            if let Some(mut snippet) = snippet {
 5848                snippet.text = new_text.to_string();
 5849                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5850            } else {
 5851                this.buffer.update(cx, |buffer, cx| {
 5852                    let auto_indent = match completion.insert_text_mode {
 5853                        Some(InsertTextMode::AS_IS) => None,
 5854                        _ => this.autoindent_mode.clone(),
 5855                    };
 5856                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5857                    buffer.edit(edits, auto_indent, cx);
 5858                });
 5859            }
 5860            for (buffer, edits) in linked_edits {
 5861                buffer.update(cx, |buffer, cx| {
 5862                    let snapshot = buffer.snapshot();
 5863                    let edits = edits
 5864                        .into_iter()
 5865                        .map(|(range, text)| {
 5866                            use text::ToPoint as TP;
 5867                            let end_point = TP::to_point(&range.end, &snapshot);
 5868                            let start_point = TP::to_point(&range.start, &snapshot);
 5869                            (start_point..end_point, text)
 5870                        })
 5871                        .sorted_by_key(|(range, _)| range.start);
 5872                    buffer.edit(edits, None, cx);
 5873                })
 5874            }
 5875
 5876            this.refresh_inline_completion(true, false, window, cx);
 5877        });
 5878
 5879        let show_new_completions_on_confirm = completion
 5880            .confirm
 5881            .as_ref()
 5882            .map_or(false, |confirm| confirm(intent, window, cx));
 5883        if show_new_completions_on_confirm {
 5884            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5885        }
 5886
 5887        let provider = self.completion_provider.as_ref()?;
 5888        drop(completion);
 5889        let apply_edits = provider.apply_additional_edits_for_completion(
 5890            buffer_handle,
 5891            completions_menu.completions.clone(),
 5892            candidate_id,
 5893            true,
 5894            cx,
 5895        );
 5896
 5897        let editor_settings = EditorSettings::get_global(cx);
 5898        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5899            // After the code completion is finished, users often want to know what signatures are needed.
 5900            // so we should automatically call signature_help
 5901            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5902        }
 5903
 5904        Some(cx.foreground_executor().spawn(async move {
 5905            apply_edits.await?;
 5906            Ok(())
 5907        }))
 5908    }
 5909
 5910    pub fn toggle_code_actions(
 5911        &mut self,
 5912        action: &ToggleCodeActions,
 5913        window: &mut Window,
 5914        cx: &mut Context<Self>,
 5915    ) {
 5916        let quick_launch = action.quick_launch;
 5917        let mut context_menu = self.context_menu.borrow_mut();
 5918        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5919            if code_actions.deployed_from == action.deployed_from {
 5920                // Toggle if we're selecting the same one
 5921                *context_menu = None;
 5922                cx.notify();
 5923                return;
 5924            } else {
 5925                // Otherwise, clear it and start a new one
 5926                *context_menu = None;
 5927                cx.notify();
 5928            }
 5929        }
 5930        drop(context_menu);
 5931        let snapshot = self.snapshot(window, cx);
 5932        let deployed_from = action.deployed_from.clone();
 5933        let action = action.clone();
 5934        self.completion_tasks.clear();
 5935        self.discard_inline_completion(false, cx);
 5936
 5937        let multibuffer_point = match &action.deployed_from {
 5938            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5939                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5940            }
 5941            _ => self.selections.newest::<Point>(cx).head(),
 5942        };
 5943        let Some((buffer, buffer_row)) = snapshot
 5944            .buffer_snapshot
 5945            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5946            .and_then(|(buffer_snapshot, range)| {
 5947                self.buffer()
 5948                    .read(cx)
 5949                    .buffer(buffer_snapshot.remote_id())
 5950                    .map(|buffer| (buffer, range.start.row))
 5951            })
 5952        else {
 5953            return;
 5954        };
 5955        let buffer_id = buffer.read(cx).remote_id();
 5956        let tasks = self
 5957            .tasks
 5958            .get(&(buffer_id, buffer_row))
 5959            .map(|t| Arc::new(t.to_owned()));
 5960
 5961        if !self.focus_handle.is_focused(window) {
 5962            return;
 5963        }
 5964        let project = self.project.clone();
 5965
 5966        let code_actions_task = match deployed_from {
 5967            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5968            _ => self.code_actions(buffer_row, window, cx),
 5969        };
 5970
 5971        let runnable_task = match deployed_from {
 5972            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5973            _ => {
 5974                let mut task_context_task = Task::ready(None);
 5975                if let Some(tasks) = &tasks {
 5976                    if let Some(project) = project {
 5977                        task_context_task =
 5978                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5979                    }
 5980                }
 5981
 5982                cx.spawn_in(window, {
 5983                    let buffer = buffer.clone();
 5984                    async move |editor, cx| {
 5985                        let task_context = task_context_task.await;
 5986
 5987                        let resolved_tasks =
 5988                            tasks
 5989                                .zip(task_context.clone())
 5990                                .map(|(tasks, task_context)| ResolvedTasks {
 5991                                    templates: tasks.resolve(&task_context).collect(),
 5992                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5993                                        multibuffer_point.row,
 5994                                        tasks.column,
 5995                                    )),
 5996                                });
 5997                        let debug_scenarios = editor
 5998                            .update(cx, |editor, cx| {
 5999                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6000                            })?
 6001                            .await;
 6002                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6003                    }
 6004                })
 6005            }
 6006        };
 6007
 6008        cx.spawn_in(window, async move |editor, cx| {
 6009            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6010            let code_actions = code_actions_task.await;
 6011            let spawn_straight_away = quick_launch
 6012                && resolved_tasks
 6013                    .as_ref()
 6014                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6015                && code_actions
 6016                    .as_ref()
 6017                    .map_or(true, |actions| actions.is_empty())
 6018                && debug_scenarios.is_empty();
 6019
 6020            editor.update_in(cx, |editor, window, cx| {
 6021                crate::hover_popover::hide_hover(editor, cx);
 6022                let actions = CodeActionContents::new(
 6023                    resolved_tasks,
 6024                    code_actions,
 6025                    debug_scenarios,
 6026                    task_context.unwrap_or_default(),
 6027                );
 6028
 6029                // Don't show the menu if there are no actions available
 6030                if actions.is_empty() {
 6031                    cx.notify();
 6032                    return Task::ready(Ok(()));
 6033                }
 6034
 6035                *editor.context_menu.borrow_mut() =
 6036                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6037                        buffer,
 6038                        actions,
 6039                        selected_item: Default::default(),
 6040                        scroll_handle: UniformListScrollHandle::default(),
 6041                        deployed_from,
 6042                    }));
 6043                cx.notify();
 6044                if spawn_straight_away {
 6045                    if let Some(task) = editor.confirm_code_action(
 6046                        &ConfirmCodeAction { item_ix: Some(0) },
 6047                        window,
 6048                        cx,
 6049                    ) {
 6050                        return task;
 6051                    }
 6052                }
 6053
 6054                Task::ready(Ok(()))
 6055            })
 6056        })
 6057        .detach_and_log_err(cx);
 6058    }
 6059
 6060    fn debug_scenarios(
 6061        &mut self,
 6062        resolved_tasks: &Option<ResolvedTasks>,
 6063        buffer: &Entity<Buffer>,
 6064        cx: &mut App,
 6065    ) -> Task<Vec<task::DebugScenario>> {
 6066        maybe!({
 6067            let project = self.project.as_ref()?;
 6068            let dap_store = project.read(cx).dap_store();
 6069            let mut scenarios = vec![];
 6070            let resolved_tasks = resolved_tasks.as_ref()?;
 6071            let buffer = buffer.read(cx);
 6072            let language = buffer.language()?;
 6073            let file = buffer.file();
 6074            let debug_adapter = language_settings(language.name().into(), file, cx)
 6075                .debuggers
 6076                .first()
 6077                .map(SharedString::from)
 6078                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6079
 6080            dap_store.update(cx, |dap_store, cx| {
 6081                for (_, task) in &resolved_tasks.templates {
 6082                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6083                        task.original_task().clone(),
 6084                        debug_adapter.clone().into(),
 6085                        task.display_label().to_owned().into(),
 6086                        cx,
 6087                    );
 6088                    scenarios.push(maybe_scenario);
 6089                }
 6090            });
 6091            Some(cx.background_spawn(async move {
 6092                let scenarios = futures::future::join_all(scenarios)
 6093                    .await
 6094                    .into_iter()
 6095                    .flatten()
 6096                    .collect::<Vec<_>>();
 6097                scenarios
 6098            }))
 6099        })
 6100        .unwrap_or_else(|| Task::ready(vec![]))
 6101    }
 6102
 6103    fn code_actions(
 6104        &mut self,
 6105        buffer_row: u32,
 6106        window: &mut Window,
 6107        cx: &mut Context<Self>,
 6108    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6109        let mut task = self.code_actions_task.take();
 6110        cx.spawn_in(window, async move |editor, cx| {
 6111            while let Some(prev_task) = task {
 6112                prev_task.await.log_err();
 6113                task = editor
 6114                    .update(cx, |this, _| this.code_actions_task.take())
 6115                    .ok()?;
 6116            }
 6117
 6118            editor
 6119                .update(cx, |editor, cx| {
 6120                    editor
 6121                        .available_code_actions
 6122                        .clone()
 6123                        .and_then(|(location, code_actions)| {
 6124                            let snapshot = location.buffer.read(cx).snapshot();
 6125                            let point_range = location.range.to_point(&snapshot);
 6126                            let point_range = point_range.start.row..=point_range.end.row;
 6127                            if point_range.contains(&buffer_row) {
 6128                                Some(code_actions)
 6129                            } else {
 6130                                None
 6131                            }
 6132                        })
 6133                })
 6134                .ok()
 6135                .flatten()
 6136        })
 6137    }
 6138
 6139    pub fn confirm_code_action(
 6140        &mut self,
 6141        action: &ConfirmCodeAction,
 6142        window: &mut Window,
 6143        cx: &mut Context<Self>,
 6144    ) -> Option<Task<Result<()>>> {
 6145        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6146
 6147        let actions_menu =
 6148            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6149                menu
 6150            } else {
 6151                return None;
 6152            };
 6153
 6154        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6155        let action = actions_menu.actions.get(action_ix)?;
 6156        let title = action.label();
 6157        let buffer = actions_menu.buffer;
 6158        let workspace = self.workspace()?;
 6159
 6160        match action {
 6161            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6162                workspace.update(cx, |workspace, cx| {
 6163                    workspace.schedule_resolved_task(
 6164                        task_source_kind,
 6165                        resolved_task,
 6166                        false,
 6167                        window,
 6168                        cx,
 6169                    );
 6170
 6171                    Some(Task::ready(Ok(())))
 6172                })
 6173            }
 6174            CodeActionsItem::CodeAction {
 6175                excerpt_id,
 6176                action,
 6177                provider,
 6178            } => {
 6179                let apply_code_action =
 6180                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6181                let workspace = workspace.downgrade();
 6182                Some(cx.spawn_in(window, async move |editor, cx| {
 6183                    let project_transaction = apply_code_action.await?;
 6184                    Self::open_project_transaction(
 6185                        &editor,
 6186                        workspace,
 6187                        project_transaction,
 6188                        title,
 6189                        cx,
 6190                    )
 6191                    .await
 6192                }))
 6193            }
 6194            CodeActionsItem::DebugScenario(scenario) => {
 6195                let context = actions_menu.actions.context.clone();
 6196
 6197                workspace.update(cx, |workspace, cx| {
 6198                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6199                    workspace.start_debug_session(
 6200                        scenario,
 6201                        context,
 6202                        Some(buffer),
 6203                        None,
 6204                        window,
 6205                        cx,
 6206                    );
 6207                });
 6208                Some(Task::ready(Ok(())))
 6209            }
 6210        }
 6211    }
 6212
 6213    pub async fn open_project_transaction(
 6214        this: &WeakEntity<Editor>,
 6215        workspace: WeakEntity<Workspace>,
 6216        transaction: ProjectTransaction,
 6217        title: String,
 6218        cx: &mut AsyncWindowContext,
 6219    ) -> Result<()> {
 6220        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6221        cx.update(|_, cx| {
 6222            entries.sort_unstable_by_key(|(buffer, _)| {
 6223                buffer.read(cx).file().map(|f| f.path().clone())
 6224            });
 6225        })?;
 6226
 6227        // If the project transaction's edits are all contained within this editor, then
 6228        // avoid opening a new editor to display them.
 6229
 6230        if let Some((buffer, transaction)) = entries.first() {
 6231            if entries.len() == 1 {
 6232                let excerpt = this.update(cx, |editor, cx| {
 6233                    editor
 6234                        .buffer()
 6235                        .read(cx)
 6236                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6237                })?;
 6238                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6239                    if excerpted_buffer == *buffer {
 6240                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6241                            let excerpt_range = excerpt_range.to_offset(buffer);
 6242                            buffer
 6243                                .edited_ranges_for_transaction::<usize>(transaction)
 6244                                .all(|range| {
 6245                                    excerpt_range.start <= range.start
 6246                                        && excerpt_range.end >= range.end
 6247                                })
 6248                        })?;
 6249
 6250                        if all_edits_within_excerpt {
 6251                            return Ok(());
 6252                        }
 6253                    }
 6254                }
 6255            }
 6256        } else {
 6257            return Ok(());
 6258        }
 6259
 6260        let mut ranges_to_highlight = Vec::new();
 6261        let excerpt_buffer = cx.new(|cx| {
 6262            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6263            for (buffer_handle, transaction) in &entries {
 6264                let edited_ranges = buffer_handle
 6265                    .read(cx)
 6266                    .edited_ranges_for_transaction::<Point>(transaction)
 6267                    .collect::<Vec<_>>();
 6268                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6269                    PathKey::for_buffer(buffer_handle, cx),
 6270                    buffer_handle.clone(),
 6271                    edited_ranges,
 6272                    DEFAULT_MULTIBUFFER_CONTEXT,
 6273                    cx,
 6274                );
 6275
 6276                ranges_to_highlight.extend(ranges);
 6277            }
 6278            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6279            multibuffer
 6280        })?;
 6281
 6282        workspace.update_in(cx, |workspace, window, cx| {
 6283            let project = workspace.project().clone();
 6284            let editor =
 6285                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6286            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6287            editor.update(cx, |editor, cx| {
 6288                editor.highlight_background::<Self>(
 6289                    &ranges_to_highlight,
 6290                    |theme| theme.colors().editor_highlighted_line_background,
 6291                    cx,
 6292                );
 6293            });
 6294        })?;
 6295
 6296        Ok(())
 6297    }
 6298
 6299    pub fn clear_code_action_providers(&mut self) {
 6300        self.code_action_providers.clear();
 6301        self.available_code_actions.take();
 6302    }
 6303
 6304    pub fn add_code_action_provider(
 6305        &mut self,
 6306        provider: Rc<dyn CodeActionProvider>,
 6307        window: &mut Window,
 6308        cx: &mut Context<Self>,
 6309    ) {
 6310        if self
 6311            .code_action_providers
 6312            .iter()
 6313            .any(|existing_provider| existing_provider.id() == provider.id())
 6314        {
 6315            return;
 6316        }
 6317
 6318        self.code_action_providers.push(provider);
 6319        self.refresh_code_actions(window, cx);
 6320    }
 6321
 6322    pub fn remove_code_action_provider(
 6323        &mut self,
 6324        id: Arc<str>,
 6325        window: &mut Window,
 6326        cx: &mut Context<Self>,
 6327    ) {
 6328        self.code_action_providers
 6329            .retain(|provider| provider.id() != id);
 6330        self.refresh_code_actions(window, cx);
 6331    }
 6332
 6333    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6334        !self.code_action_providers.is_empty()
 6335            && EditorSettings::get_global(cx).toolbar.code_actions
 6336    }
 6337
 6338    pub fn has_available_code_actions(&self) -> bool {
 6339        self.available_code_actions
 6340            .as_ref()
 6341            .is_some_and(|(_, actions)| !actions.is_empty())
 6342    }
 6343
 6344    fn render_inline_code_actions(
 6345        &self,
 6346        icon_size: ui::IconSize,
 6347        display_row: DisplayRow,
 6348        is_active: bool,
 6349        cx: &mut Context<Self>,
 6350    ) -> AnyElement {
 6351        let show_tooltip = !self.context_menu_visible();
 6352        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6353            .icon_size(icon_size)
 6354            .shape(ui::IconButtonShape::Square)
 6355            .style(ButtonStyle::Transparent)
 6356            .icon_color(ui::Color::Hidden)
 6357            .toggle_state(is_active)
 6358            .when(show_tooltip, |this| {
 6359                this.tooltip({
 6360                    let focus_handle = self.focus_handle.clone();
 6361                    move |window, cx| {
 6362                        Tooltip::for_action_in(
 6363                            "Toggle Code Actions",
 6364                            &ToggleCodeActions {
 6365                                deployed_from: None,
 6366                                quick_launch: false,
 6367                            },
 6368                            &focus_handle,
 6369                            window,
 6370                            cx,
 6371                        )
 6372                    }
 6373                })
 6374            })
 6375            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6376                window.focus(&editor.focus_handle(cx));
 6377                editor.toggle_code_actions(
 6378                    &crate::actions::ToggleCodeActions {
 6379                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6380                            display_row,
 6381                        )),
 6382                        quick_launch: false,
 6383                    },
 6384                    window,
 6385                    cx,
 6386                );
 6387            }))
 6388            .into_any_element()
 6389    }
 6390
 6391    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6392        &self.context_menu
 6393    }
 6394
 6395    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6396        let newest_selection = self.selections.newest_anchor().clone();
 6397        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6398        let buffer = self.buffer.read(cx);
 6399        if newest_selection.head().diff_base_anchor.is_some() {
 6400            return None;
 6401        }
 6402        let (start_buffer, start) =
 6403            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6404        let (end_buffer, end) =
 6405            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6406        if start_buffer != end_buffer {
 6407            return None;
 6408        }
 6409
 6410        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6411            cx.background_executor()
 6412                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6413                .await;
 6414
 6415            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6416                let providers = this.code_action_providers.clone();
 6417                let tasks = this
 6418                    .code_action_providers
 6419                    .iter()
 6420                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6421                    .collect::<Vec<_>>();
 6422                (providers, tasks)
 6423            })?;
 6424
 6425            let mut actions = Vec::new();
 6426            for (provider, provider_actions) in
 6427                providers.into_iter().zip(future::join_all(tasks).await)
 6428            {
 6429                if let Some(provider_actions) = provider_actions.log_err() {
 6430                    actions.extend(provider_actions.into_iter().map(|action| {
 6431                        AvailableCodeAction {
 6432                            excerpt_id: newest_selection.start.excerpt_id,
 6433                            action,
 6434                            provider: provider.clone(),
 6435                        }
 6436                    }));
 6437                }
 6438            }
 6439
 6440            this.update(cx, |this, cx| {
 6441                this.available_code_actions = if actions.is_empty() {
 6442                    None
 6443                } else {
 6444                    Some((
 6445                        Location {
 6446                            buffer: start_buffer,
 6447                            range: start..end,
 6448                        },
 6449                        actions.into(),
 6450                    ))
 6451                };
 6452                cx.notify();
 6453            })
 6454        }));
 6455        None
 6456    }
 6457
 6458    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6459        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6460            self.show_git_blame_inline = false;
 6461
 6462            self.show_git_blame_inline_delay_task =
 6463                Some(cx.spawn_in(window, async move |this, cx| {
 6464                    cx.background_executor().timer(delay).await;
 6465
 6466                    this.update(cx, |this, cx| {
 6467                        this.show_git_blame_inline = true;
 6468                        cx.notify();
 6469                    })
 6470                    .log_err();
 6471                }));
 6472        }
 6473    }
 6474
 6475    fn show_blame_popover(
 6476        &mut self,
 6477        blame_entry: &BlameEntry,
 6478        position: gpui::Point<Pixels>,
 6479        cx: &mut Context<Self>,
 6480    ) {
 6481        if let Some(state) = &mut self.inline_blame_popover {
 6482            state.hide_task.take();
 6483        } else {
 6484            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6485            let blame_entry = blame_entry.clone();
 6486            let show_task = cx.spawn(async move |editor, cx| {
 6487                cx.background_executor()
 6488                    .timer(std::time::Duration::from_millis(delay))
 6489                    .await;
 6490                editor
 6491                    .update(cx, |editor, cx| {
 6492                        editor.inline_blame_popover_show_task.take();
 6493                        let Some(blame) = editor.blame.as_ref() else {
 6494                            return;
 6495                        };
 6496                        let blame = blame.read(cx);
 6497                        let details = blame.details_for_entry(&blame_entry);
 6498                        let markdown = cx.new(|cx| {
 6499                            Markdown::new(
 6500                                details
 6501                                    .as_ref()
 6502                                    .map(|message| message.message.clone())
 6503                                    .unwrap_or_default(),
 6504                                None,
 6505                                None,
 6506                                cx,
 6507                            )
 6508                        });
 6509                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6510                            position,
 6511                            hide_task: None,
 6512                            popover_bounds: None,
 6513                            popover_state: InlineBlamePopoverState {
 6514                                scroll_handle: ScrollHandle::new(),
 6515                                commit_message: details,
 6516                                markdown,
 6517                            },
 6518                        });
 6519                        cx.notify();
 6520                    })
 6521                    .ok();
 6522            });
 6523            self.inline_blame_popover_show_task = Some(show_task);
 6524        }
 6525    }
 6526
 6527    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6528        self.inline_blame_popover_show_task.take();
 6529        if let Some(state) = &mut self.inline_blame_popover {
 6530            let hide_task = cx.spawn(async move |editor, cx| {
 6531                cx.background_executor()
 6532                    .timer(std::time::Duration::from_millis(100))
 6533                    .await;
 6534                editor
 6535                    .update(cx, |editor, cx| {
 6536                        editor.inline_blame_popover.take();
 6537                        cx.notify();
 6538                    })
 6539                    .ok();
 6540            });
 6541            state.hide_task = Some(hide_task);
 6542        }
 6543    }
 6544
 6545    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6546        if self.pending_rename.is_some() {
 6547            return None;
 6548        }
 6549
 6550        let provider = self.semantics_provider.clone()?;
 6551        let buffer = self.buffer.read(cx);
 6552        let newest_selection = self.selections.newest_anchor().clone();
 6553        let cursor_position = newest_selection.head();
 6554        let (cursor_buffer, cursor_buffer_position) =
 6555            buffer.text_anchor_for_position(cursor_position, cx)?;
 6556        let (tail_buffer, tail_buffer_position) =
 6557            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6558        if cursor_buffer != tail_buffer {
 6559            return None;
 6560        }
 6561
 6562        let snapshot = cursor_buffer.read(cx).snapshot();
 6563        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6564        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6565        if start_word_range != end_word_range {
 6566            self.document_highlights_task.take();
 6567            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6568            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6569            return None;
 6570        }
 6571
 6572        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6573        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6574            cx.background_executor()
 6575                .timer(Duration::from_millis(debounce))
 6576                .await;
 6577
 6578            let highlights = if let Some(highlights) = cx
 6579                .update(|cx| {
 6580                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6581                })
 6582                .ok()
 6583                .flatten()
 6584            {
 6585                highlights.await.log_err()
 6586            } else {
 6587                None
 6588            };
 6589
 6590            if let Some(highlights) = highlights {
 6591                this.update(cx, |this, cx| {
 6592                    if this.pending_rename.is_some() {
 6593                        return;
 6594                    }
 6595
 6596                    let buffer_id = cursor_position.buffer_id;
 6597                    let buffer = this.buffer.read(cx);
 6598                    if !buffer
 6599                        .text_anchor_for_position(cursor_position, cx)
 6600                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6601                    {
 6602                        return;
 6603                    }
 6604
 6605                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6606                    let mut write_ranges = Vec::new();
 6607                    let mut read_ranges = Vec::new();
 6608                    for highlight in highlights {
 6609                        for (excerpt_id, excerpt_range) in
 6610                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6611                        {
 6612                            let start = highlight
 6613                                .range
 6614                                .start
 6615                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6616                            let end = highlight
 6617                                .range
 6618                                .end
 6619                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6620                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6621                                continue;
 6622                            }
 6623
 6624                            let range = Anchor {
 6625                                buffer_id,
 6626                                excerpt_id,
 6627                                text_anchor: start,
 6628                                diff_base_anchor: None,
 6629                            }..Anchor {
 6630                                buffer_id,
 6631                                excerpt_id,
 6632                                text_anchor: end,
 6633                                diff_base_anchor: None,
 6634                            };
 6635                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6636                                write_ranges.push(range);
 6637                            } else {
 6638                                read_ranges.push(range);
 6639                            }
 6640                        }
 6641                    }
 6642
 6643                    this.highlight_background::<DocumentHighlightRead>(
 6644                        &read_ranges,
 6645                        |theme| theme.colors().editor_document_highlight_read_background,
 6646                        cx,
 6647                    );
 6648                    this.highlight_background::<DocumentHighlightWrite>(
 6649                        &write_ranges,
 6650                        |theme| theme.colors().editor_document_highlight_write_background,
 6651                        cx,
 6652                    );
 6653                    cx.notify();
 6654                })
 6655                .log_err();
 6656            }
 6657        }));
 6658        None
 6659    }
 6660
 6661    fn prepare_highlight_query_from_selection(
 6662        &mut self,
 6663        cx: &mut Context<Editor>,
 6664    ) -> Option<(String, Range<Anchor>)> {
 6665        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6666            return None;
 6667        }
 6668        if !EditorSettings::get_global(cx).selection_highlight {
 6669            return None;
 6670        }
 6671        if self.selections.count() != 1 || self.selections.line_mode {
 6672            return None;
 6673        }
 6674        let selection = self.selections.newest::<Point>(cx);
 6675        if selection.is_empty() || selection.start.row != selection.end.row {
 6676            return None;
 6677        }
 6678        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6679        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6680        let query = multi_buffer_snapshot
 6681            .text_for_range(selection_anchor_range.clone())
 6682            .collect::<String>();
 6683        if query.trim().is_empty() {
 6684            return None;
 6685        }
 6686        Some((query, selection_anchor_range))
 6687    }
 6688
 6689    fn update_selection_occurrence_highlights(
 6690        &mut self,
 6691        query_text: String,
 6692        query_range: Range<Anchor>,
 6693        multi_buffer_range_to_query: Range<Point>,
 6694        use_debounce: bool,
 6695        window: &mut Window,
 6696        cx: &mut Context<Editor>,
 6697    ) -> Task<()> {
 6698        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6699        cx.spawn_in(window, async move |editor, cx| {
 6700            if use_debounce {
 6701                cx.background_executor()
 6702                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6703                    .await;
 6704            }
 6705            let match_task = cx.background_spawn(async move {
 6706                let buffer_ranges = multi_buffer_snapshot
 6707                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6708                    .into_iter()
 6709                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6710                let mut match_ranges = Vec::new();
 6711                let Ok(regex) = project::search::SearchQuery::text(
 6712                    query_text.clone(),
 6713                    false,
 6714                    false,
 6715                    false,
 6716                    Default::default(),
 6717                    Default::default(),
 6718                    false,
 6719                    None,
 6720                ) else {
 6721                    return Vec::default();
 6722                };
 6723                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6724                    match_ranges.extend(
 6725                        regex
 6726                            .search(&buffer_snapshot, Some(search_range.clone()))
 6727                            .await
 6728                            .into_iter()
 6729                            .filter_map(|match_range| {
 6730                                let match_start = buffer_snapshot
 6731                                    .anchor_after(search_range.start + match_range.start);
 6732                                let match_end = buffer_snapshot
 6733                                    .anchor_before(search_range.start + match_range.end);
 6734                                let match_anchor_range = Anchor::range_in_buffer(
 6735                                    excerpt_id,
 6736                                    buffer_snapshot.remote_id(),
 6737                                    match_start..match_end,
 6738                                );
 6739                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6740                            }),
 6741                    );
 6742                }
 6743                match_ranges
 6744            });
 6745            let match_ranges = match_task.await;
 6746            editor
 6747                .update_in(cx, |editor, _, cx| {
 6748                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6749                    if !match_ranges.is_empty() {
 6750                        editor.highlight_background::<SelectedTextHighlight>(
 6751                            &match_ranges,
 6752                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6753                            cx,
 6754                        )
 6755                    }
 6756                })
 6757                .log_err();
 6758        })
 6759    }
 6760
 6761    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6762        struct NewlineFold;
 6763        let type_id = std::any::TypeId::of::<NewlineFold>();
 6764        if !self.mode.is_single_line() {
 6765            return;
 6766        }
 6767        let snapshot = self.snapshot(window, cx);
 6768        if snapshot.buffer_snapshot.max_point().row == 0 {
 6769            return;
 6770        }
 6771        let task = cx.background_spawn(async move {
 6772            let new_newlines = snapshot
 6773                .buffer_chars_at(0)
 6774                .filter_map(|(c, i)| {
 6775                    if c == '\n' {
 6776                        Some(
 6777                            snapshot.buffer_snapshot.anchor_after(i)
 6778                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6779                        )
 6780                    } else {
 6781                        None
 6782                    }
 6783                })
 6784                .collect::<Vec<_>>();
 6785            let existing_newlines = snapshot
 6786                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6787                .filter_map(|fold| {
 6788                    if fold.placeholder.type_tag == Some(type_id) {
 6789                        Some(fold.range.start..fold.range.end)
 6790                    } else {
 6791                        None
 6792                    }
 6793                })
 6794                .collect::<Vec<_>>();
 6795
 6796            (new_newlines, existing_newlines)
 6797        });
 6798        self.folding_newlines = cx.spawn(async move |this, cx| {
 6799            let (new_newlines, existing_newlines) = task.await;
 6800            if new_newlines == existing_newlines {
 6801                return;
 6802            }
 6803            let placeholder = FoldPlaceholder {
 6804                render: Arc::new(move |_, _, cx| {
 6805                    div()
 6806                        .bg(cx.theme().status().hint_background)
 6807                        .border_b_1()
 6808                        .size_full()
 6809                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6810                        .border_color(cx.theme().status().hint)
 6811                        .child("\\n")
 6812                        .into_any()
 6813                }),
 6814                constrain_width: false,
 6815                merge_adjacent: false,
 6816                type_tag: Some(type_id),
 6817            };
 6818            let creases = new_newlines
 6819                .into_iter()
 6820                .map(|range| Crease::simple(range, placeholder.clone()))
 6821                .collect();
 6822            this.update(cx, |this, cx| {
 6823                this.display_map.update(cx, |display_map, cx| {
 6824                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6825                    display_map.fold(creases, cx);
 6826                });
 6827            })
 6828            .ok();
 6829        });
 6830    }
 6831
 6832    fn refresh_selected_text_highlights(
 6833        &mut self,
 6834        on_buffer_edit: bool,
 6835        window: &mut Window,
 6836        cx: &mut Context<Editor>,
 6837    ) {
 6838        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6839        else {
 6840            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6841            self.quick_selection_highlight_task.take();
 6842            self.debounced_selection_highlight_task.take();
 6843            return;
 6844        };
 6845        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6846        if on_buffer_edit
 6847            || self
 6848                .quick_selection_highlight_task
 6849                .as_ref()
 6850                .map_or(true, |(prev_anchor_range, _)| {
 6851                    prev_anchor_range != &query_range
 6852                })
 6853        {
 6854            let multi_buffer_visible_start = self
 6855                .scroll_manager
 6856                .anchor()
 6857                .anchor
 6858                .to_point(&multi_buffer_snapshot);
 6859            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6860                multi_buffer_visible_start
 6861                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6862                Bias::Left,
 6863            );
 6864            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6865            self.quick_selection_highlight_task = Some((
 6866                query_range.clone(),
 6867                self.update_selection_occurrence_highlights(
 6868                    query_text.clone(),
 6869                    query_range.clone(),
 6870                    multi_buffer_visible_range,
 6871                    false,
 6872                    window,
 6873                    cx,
 6874                ),
 6875            ));
 6876        }
 6877        if on_buffer_edit
 6878            || self
 6879                .debounced_selection_highlight_task
 6880                .as_ref()
 6881                .map_or(true, |(prev_anchor_range, _)| {
 6882                    prev_anchor_range != &query_range
 6883                })
 6884        {
 6885            let multi_buffer_start = multi_buffer_snapshot
 6886                .anchor_before(0)
 6887                .to_point(&multi_buffer_snapshot);
 6888            let multi_buffer_end = multi_buffer_snapshot
 6889                .anchor_after(multi_buffer_snapshot.len())
 6890                .to_point(&multi_buffer_snapshot);
 6891            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6892            self.debounced_selection_highlight_task = Some((
 6893                query_range.clone(),
 6894                self.update_selection_occurrence_highlights(
 6895                    query_text,
 6896                    query_range,
 6897                    multi_buffer_full_range,
 6898                    true,
 6899                    window,
 6900                    cx,
 6901                ),
 6902            ));
 6903        }
 6904    }
 6905
 6906    pub fn refresh_inline_completion(
 6907        &mut self,
 6908        debounce: bool,
 6909        user_requested: bool,
 6910        window: &mut Window,
 6911        cx: &mut Context<Self>,
 6912    ) -> Option<()> {
 6913        let provider = self.edit_prediction_provider()?;
 6914        let cursor = self.selections.newest_anchor().head();
 6915        let (buffer, cursor_buffer_position) =
 6916            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6917
 6918        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6919            self.discard_inline_completion(false, cx);
 6920            return None;
 6921        }
 6922
 6923        if !user_requested
 6924            && (!self.should_show_edit_predictions()
 6925                || !self.is_focused(window)
 6926                || buffer.read(cx).is_empty())
 6927        {
 6928            self.discard_inline_completion(false, cx);
 6929            return None;
 6930        }
 6931
 6932        self.update_visible_inline_completion(window, cx);
 6933        provider.refresh(
 6934            self.project.clone(),
 6935            buffer,
 6936            cursor_buffer_position,
 6937            debounce,
 6938            cx,
 6939        );
 6940        Some(())
 6941    }
 6942
 6943    fn show_edit_predictions_in_menu(&self) -> bool {
 6944        match self.edit_prediction_settings {
 6945            EditPredictionSettings::Disabled => false,
 6946            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6947        }
 6948    }
 6949
 6950    pub fn edit_predictions_enabled(&self) -> bool {
 6951        match self.edit_prediction_settings {
 6952            EditPredictionSettings::Disabled => false,
 6953            EditPredictionSettings::Enabled { .. } => true,
 6954        }
 6955    }
 6956
 6957    fn edit_prediction_requires_modifier(&self) -> bool {
 6958        match self.edit_prediction_settings {
 6959            EditPredictionSettings::Disabled => false,
 6960            EditPredictionSettings::Enabled {
 6961                preview_requires_modifier,
 6962                ..
 6963            } => preview_requires_modifier,
 6964        }
 6965    }
 6966
 6967    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6968        if self.edit_prediction_provider.is_none() {
 6969            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6970        } else {
 6971            let selection = self.selections.newest_anchor();
 6972            let cursor = selection.head();
 6973
 6974            if let Some((buffer, cursor_buffer_position)) =
 6975                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6976            {
 6977                self.edit_prediction_settings =
 6978                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6979            }
 6980        }
 6981    }
 6982
 6983    fn edit_prediction_settings_at_position(
 6984        &self,
 6985        buffer: &Entity<Buffer>,
 6986        buffer_position: language::Anchor,
 6987        cx: &App,
 6988    ) -> EditPredictionSettings {
 6989        if !self.mode.is_full()
 6990            || !self.show_inline_completions_override.unwrap_or(true)
 6991            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6992        {
 6993            return EditPredictionSettings::Disabled;
 6994        }
 6995
 6996        let buffer = buffer.read(cx);
 6997
 6998        let file = buffer.file();
 6999
 7000        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7001            return EditPredictionSettings::Disabled;
 7002        };
 7003
 7004        let by_provider = matches!(
 7005            self.menu_inline_completions_policy,
 7006            MenuInlineCompletionsPolicy::ByProvider
 7007        );
 7008
 7009        let show_in_menu = by_provider
 7010            && self
 7011                .edit_prediction_provider
 7012                .as_ref()
 7013                .map_or(false, |provider| {
 7014                    provider.provider.show_completions_in_menu()
 7015                });
 7016
 7017        let preview_requires_modifier =
 7018            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7019
 7020        EditPredictionSettings::Enabled {
 7021            show_in_menu,
 7022            preview_requires_modifier,
 7023        }
 7024    }
 7025
 7026    fn should_show_edit_predictions(&self) -> bool {
 7027        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7028    }
 7029
 7030    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7031        matches!(
 7032            self.edit_prediction_preview,
 7033            EditPredictionPreview::Active { .. }
 7034        )
 7035    }
 7036
 7037    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7038        let cursor = self.selections.newest_anchor().head();
 7039        if let Some((buffer, cursor_position)) =
 7040            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7041        {
 7042            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7043        } else {
 7044            false
 7045        }
 7046    }
 7047
 7048    pub fn supports_minimap(&self, cx: &App) -> bool {
 7049        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7050    }
 7051
 7052    fn edit_predictions_enabled_in_buffer(
 7053        &self,
 7054        buffer: &Entity<Buffer>,
 7055        buffer_position: language::Anchor,
 7056        cx: &App,
 7057    ) -> bool {
 7058        maybe!({
 7059            if self.read_only(cx) {
 7060                return Some(false);
 7061            }
 7062            let provider = self.edit_prediction_provider()?;
 7063            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7064                return Some(false);
 7065            }
 7066            let buffer = buffer.read(cx);
 7067            let Some(file) = buffer.file() else {
 7068                return Some(true);
 7069            };
 7070            let settings = all_language_settings(Some(file), cx);
 7071            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7072        })
 7073        .unwrap_or(false)
 7074    }
 7075
 7076    fn cycle_inline_completion(
 7077        &mut self,
 7078        direction: Direction,
 7079        window: &mut Window,
 7080        cx: &mut Context<Self>,
 7081    ) -> Option<()> {
 7082        let provider = self.edit_prediction_provider()?;
 7083        let cursor = self.selections.newest_anchor().head();
 7084        let (buffer, cursor_buffer_position) =
 7085            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7086        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7087            return None;
 7088        }
 7089
 7090        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7091        self.update_visible_inline_completion(window, cx);
 7092
 7093        Some(())
 7094    }
 7095
 7096    pub fn show_inline_completion(
 7097        &mut self,
 7098        _: &ShowEditPrediction,
 7099        window: &mut Window,
 7100        cx: &mut Context<Self>,
 7101    ) {
 7102        if !self.has_active_inline_completion() {
 7103            self.refresh_inline_completion(false, true, window, cx);
 7104            return;
 7105        }
 7106
 7107        self.update_visible_inline_completion(window, cx);
 7108    }
 7109
 7110    pub fn display_cursor_names(
 7111        &mut self,
 7112        _: &DisplayCursorNames,
 7113        window: &mut Window,
 7114        cx: &mut Context<Self>,
 7115    ) {
 7116        self.show_cursor_names(window, cx);
 7117    }
 7118
 7119    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7120        self.show_cursor_names = true;
 7121        cx.notify();
 7122        cx.spawn_in(window, async move |this, cx| {
 7123            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7124            this.update(cx, |this, cx| {
 7125                this.show_cursor_names = false;
 7126                cx.notify()
 7127            })
 7128            .ok()
 7129        })
 7130        .detach();
 7131    }
 7132
 7133    pub fn next_edit_prediction(
 7134        &mut self,
 7135        _: &NextEditPrediction,
 7136        window: &mut Window,
 7137        cx: &mut Context<Self>,
 7138    ) {
 7139        if self.has_active_inline_completion() {
 7140            self.cycle_inline_completion(Direction::Next, window, cx);
 7141        } else {
 7142            let is_copilot_disabled = self
 7143                .refresh_inline_completion(false, true, window, cx)
 7144                .is_none();
 7145            if is_copilot_disabled {
 7146                cx.propagate();
 7147            }
 7148        }
 7149    }
 7150
 7151    pub fn previous_edit_prediction(
 7152        &mut self,
 7153        _: &PreviousEditPrediction,
 7154        window: &mut Window,
 7155        cx: &mut Context<Self>,
 7156    ) {
 7157        if self.has_active_inline_completion() {
 7158            self.cycle_inline_completion(Direction::Prev, window, cx);
 7159        } else {
 7160            let is_copilot_disabled = self
 7161                .refresh_inline_completion(false, true, window, cx)
 7162                .is_none();
 7163            if is_copilot_disabled {
 7164                cx.propagate();
 7165            }
 7166        }
 7167    }
 7168
 7169    pub fn accept_edit_prediction(
 7170        &mut self,
 7171        _: &AcceptEditPrediction,
 7172        window: &mut Window,
 7173        cx: &mut Context<Self>,
 7174    ) {
 7175        if self.show_edit_predictions_in_menu() {
 7176            self.hide_context_menu(window, cx);
 7177        }
 7178
 7179        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7180            return;
 7181        };
 7182
 7183        self.report_inline_completion_event(
 7184            active_inline_completion.completion_id.clone(),
 7185            true,
 7186            cx,
 7187        );
 7188
 7189        match &active_inline_completion.completion {
 7190            InlineCompletion::Move { target, .. } => {
 7191                let target = *target;
 7192
 7193                if let Some(position_map) = &self.last_position_map {
 7194                    if position_map
 7195                        .visible_row_range
 7196                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7197                        || !self.edit_prediction_requires_modifier()
 7198                    {
 7199                        self.unfold_ranges(&[target..target], true, false, cx);
 7200                        // Note that this is also done in vim's handler of the Tab action.
 7201                        self.change_selections(
 7202                            SelectionEffects::scroll(Autoscroll::newest()),
 7203                            window,
 7204                            cx,
 7205                            |selections| {
 7206                                selections.select_anchor_ranges([target..target]);
 7207                            },
 7208                        );
 7209                        self.clear_row_highlights::<EditPredictionPreview>();
 7210
 7211                        self.edit_prediction_preview
 7212                            .set_previous_scroll_position(None);
 7213                    } else {
 7214                        self.edit_prediction_preview
 7215                            .set_previous_scroll_position(Some(
 7216                                position_map.snapshot.scroll_anchor,
 7217                            ));
 7218
 7219                        self.highlight_rows::<EditPredictionPreview>(
 7220                            target..target,
 7221                            cx.theme().colors().editor_highlighted_line_background,
 7222                            RowHighlightOptions {
 7223                                autoscroll: true,
 7224                                ..Default::default()
 7225                            },
 7226                            cx,
 7227                        );
 7228                        self.request_autoscroll(Autoscroll::fit(), cx);
 7229                    }
 7230                }
 7231            }
 7232            InlineCompletion::Edit { edits, .. } => {
 7233                if let Some(provider) = self.edit_prediction_provider() {
 7234                    provider.accept(cx);
 7235                }
 7236
 7237                // Store the transaction ID and selections before applying the edit
 7238                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7239
 7240                let snapshot = self.buffer.read(cx).snapshot(cx);
 7241                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7242
 7243                self.buffer.update(cx, |buffer, cx| {
 7244                    buffer.edit(edits.iter().cloned(), None, cx)
 7245                });
 7246
 7247                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7248                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7249                });
 7250
 7251                let selections = self.selections.disjoint_anchors();
 7252                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7253                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7254                    if has_new_transaction {
 7255                        self.selection_history
 7256                            .insert_transaction(transaction_id_now, selections);
 7257                    }
 7258                }
 7259
 7260                self.update_visible_inline_completion(window, cx);
 7261                if self.active_inline_completion.is_none() {
 7262                    self.refresh_inline_completion(true, true, window, cx);
 7263                }
 7264
 7265                cx.notify();
 7266            }
 7267        }
 7268
 7269        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7270    }
 7271
 7272    pub fn accept_partial_inline_completion(
 7273        &mut self,
 7274        _: &AcceptPartialEditPrediction,
 7275        window: &mut Window,
 7276        cx: &mut Context<Self>,
 7277    ) {
 7278        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7279            return;
 7280        };
 7281        if self.selections.count() != 1 {
 7282            return;
 7283        }
 7284
 7285        self.report_inline_completion_event(
 7286            active_inline_completion.completion_id.clone(),
 7287            true,
 7288            cx,
 7289        );
 7290
 7291        match &active_inline_completion.completion {
 7292            InlineCompletion::Move { target, .. } => {
 7293                let target = *target;
 7294                self.change_selections(
 7295                    SelectionEffects::scroll(Autoscroll::newest()),
 7296                    window,
 7297                    cx,
 7298                    |selections| {
 7299                        selections.select_anchor_ranges([target..target]);
 7300                    },
 7301                );
 7302            }
 7303            InlineCompletion::Edit { edits, .. } => {
 7304                // Find an insertion that starts at the cursor position.
 7305                let snapshot = self.buffer.read(cx).snapshot(cx);
 7306                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7307                let insertion = edits.iter().find_map(|(range, text)| {
 7308                    let range = range.to_offset(&snapshot);
 7309                    if range.is_empty() && range.start == cursor_offset {
 7310                        Some(text)
 7311                    } else {
 7312                        None
 7313                    }
 7314                });
 7315
 7316                if let Some(text) = insertion {
 7317                    let mut partial_completion = text
 7318                        .chars()
 7319                        .by_ref()
 7320                        .take_while(|c| c.is_alphabetic())
 7321                        .collect::<String>();
 7322                    if partial_completion.is_empty() {
 7323                        partial_completion = text
 7324                            .chars()
 7325                            .by_ref()
 7326                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7327                            .collect::<String>();
 7328                    }
 7329
 7330                    cx.emit(EditorEvent::InputHandled {
 7331                        utf16_range_to_replace: None,
 7332                        text: partial_completion.clone().into(),
 7333                    });
 7334
 7335                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7336
 7337                    self.refresh_inline_completion(true, true, window, cx);
 7338                    cx.notify();
 7339                } else {
 7340                    self.accept_edit_prediction(&Default::default(), window, cx);
 7341                }
 7342            }
 7343        }
 7344    }
 7345
 7346    fn discard_inline_completion(
 7347        &mut self,
 7348        should_report_inline_completion_event: bool,
 7349        cx: &mut Context<Self>,
 7350    ) -> bool {
 7351        if should_report_inline_completion_event {
 7352            let completion_id = self
 7353                .active_inline_completion
 7354                .as_ref()
 7355                .and_then(|active_completion| active_completion.completion_id.clone());
 7356
 7357            self.report_inline_completion_event(completion_id, false, cx);
 7358        }
 7359
 7360        if let Some(provider) = self.edit_prediction_provider() {
 7361            provider.discard(cx);
 7362        }
 7363
 7364        self.take_active_inline_completion(cx)
 7365    }
 7366
 7367    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7368        let Some(provider) = self.edit_prediction_provider() else {
 7369            return;
 7370        };
 7371
 7372        let Some((_, buffer, _)) = self
 7373            .buffer
 7374            .read(cx)
 7375            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7376        else {
 7377            return;
 7378        };
 7379
 7380        let extension = buffer
 7381            .read(cx)
 7382            .file()
 7383            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7384
 7385        let event_type = match accepted {
 7386            true => "Edit Prediction Accepted",
 7387            false => "Edit Prediction Discarded",
 7388        };
 7389        telemetry::event!(
 7390            event_type,
 7391            provider = provider.name(),
 7392            prediction_id = id,
 7393            suggestion_accepted = accepted,
 7394            file_extension = extension,
 7395        );
 7396    }
 7397
 7398    pub fn has_active_inline_completion(&self) -> bool {
 7399        self.active_inline_completion.is_some()
 7400    }
 7401
 7402    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7403        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7404            return false;
 7405        };
 7406
 7407        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7408        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7409        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7410        true
 7411    }
 7412
 7413    /// Returns true when we're displaying the edit prediction popover below the cursor
 7414    /// like we are not previewing and the LSP autocomplete menu is visible
 7415    /// or we are in `when_holding_modifier` mode.
 7416    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7417        if self.edit_prediction_preview_is_active()
 7418            || !self.show_edit_predictions_in_menu()
 7419            || !self.edit_predictions_enabled()
 7420        {
 7421            return false;
 7422        }
 7423
 7424        if self.has_visible_completions_menu() {
 7425            return true;
 7426        }
 7427
 7428        has_completion && self.edit_prediction_requires_modifier()
 7429    }
 7430
 7431    fn handle_modifiers_changed(
 7432        &mut self,
 7433        modifiers: Modifiers,
 7434        position_map: &PositionMap,
 7435        window: &mut Window,
 7436        cx: &mut Context<Self>,
 7437    ) {
 7438        if self.show_edit_predictions_in_menu() {
 7439            self.update_edit_prediction_preview(&modifiers, window, cx);
 7440        }
 7441
 7442        self.update_selection_mode(&modifiers, position_map, window, cx);
 7443
 7444        let mouse_position = window.mouse_position();
 7445        if !position_map.text_hitbox.is_hovered(window) {
 7446            return;
 7447        }
 7448
 7449        self.update_hovered_link(
 7450            position_map.point_for_position(mouse_position),
 7451            &position_map.snapshot,
 7452            modifiers,
 7453            window,
 7454            cx,
 7455        )
 7456    }
 7457
 7458    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7459        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7460        if invert {
 7461            match multi_cursor_setting {
 7462                MultiCursorModifier::Alt => modifiers.alt,
 7463                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7464            }
 7465        } else {
 7466            match multi_cursor_setting {
 7467                MultiCursorModifier::Alt => modifiers.secondary(),
 7468                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7469            }
 7470        }
 7471    }
 7472
 7473    fn columnar_selection_mode(
 7474        modifiers: &Modifiers,
 7475        cx: &mut Context<Self>,
 7476    ) -> Option<ColumnarMode> {
 7477        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7478            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7479                Some(ColumnarMode::FromMouse)
 7480            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7481                Some(ColumnarMode::FromSelection)
 7482            } else {
 7483                None
 7484            }
 7485        } else {
 7486            None
 7487        }
 7488    }
 7489
 7490    fn update_selection_mode(
 7491        &mut self,
 7492        modifiers: &Modifiers,
 7493        position_map: &PositionMap,
 7494        window: &mut Window,
 7495        cx: &mut Context<Self>,
 7496    ) {
 7497        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7498            return;
 7499        };
 7500        if self.selections.pending.is_none() {
 7501            return;
 7502        }
 7503
 7504        let mouse_position = window.mouse_position();
 7505        let point_for_position = position_map.point_for_position(mouse_position);
 7506        let position = point_for_position.previous_valid;
 7507
 7508        self.select(
 7509            SelectPhase::BeginColumnar {
 7510                position,
 7511                reset: false,
 7512                mode,
 7513                goal_column: point_for_position.exact_unclipped.column(),
 7514            },
 7515            window,
 7516            cx,
 7517        );
 7518    }
 7519
 7520    fn update_edit_prediction_preview(
 7521        &mut self,
 7522        modifiers: &Modifiers,
 7523        window: &mut Window,
 7524        cx: &mut Context<Self>,
 7525    ) {
 7526        let mut modifiers_held = false;
 7527        if let Some(accept_keystroke) = self
 7528            .accept_edit_prediction_keybind(false, window, cx)
 7529            .keystroke()
 7530        {
 7531            modifiers_held = modifiers_held
 7532                || (&accept_keystroke.modifiers == modifiers
 7533                    && accept_keystroke.modifiers.modified());
 7534        };
 7535        if let Some(accept_partial_keystroke) = self
 7536            .accept_edit_prediction_keybind(true, window, cx)
 7537            .keystroke()
 7538        {
 7539            modifiers_held = modifiers_held
 7540                || (&accept_partial_keystroke.modifiers == modifiers
 7541                    && accept_partial_keystroke.modifiers.modified());
 7542        }
 7543
 7544        if modifiers_held {
 7545            if matches!(
 7546                self.edit_prediction_preview,
 7547                EditPredictionPreview::Inactive { .. }
 7548            ) {
 7549                self.edit_prediction_preview = EditPredictionPreview::Active {
 7550                    previous_scroll_position: None,
 7551                    since: Instant::now(),
 7552                };
 7553
 7554                self.update_visible_inline_completion(window, cx);
 7555                cx.notify();
 7556            }
 7557        } else if let EditPredictionPreview::Active {
 7558            previous_scroll_position,
 7559            since,
 7560        } = self.edit_prediction_preview
 7561        {
 7562            if let (Some(previous_scroll_position), Some(position_map)) =
 7563                (previous_scroll_position, self.last_position_map.as_ref())
 7564            {
 7565                self.set_scroll_position(
 7566                    previous_scroll_position
 7567                        .scroll_position(&position_map.snapshot.display_snapshot),
 7568                    window,
 7569                    cx,
 7570                );
 7571            }
 7572
 7573            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7574                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7575            };
 7576            self.clear_row_highlights::<EditPredictionPreview>();
 7577            self.update_visible_inline_completion(window, cx);
 7578            cx.notify();
 7579        }
 7580    }
 7581
 7582    fn update_visible_inline_completion(
 7583        &mut self,
 7584        _window: &mut Window,
 7585        cx: &mut Context<Self>,
 7586    ) -> Option<()> {
 7587        let selection = self.selections.newest_anchor();
 7588        let cursor = selection.head();
 7589        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7590        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7591        let excerpt_id = cursor.excerpt_id;
 7592
 7593        let show_in_menu = self.show_edit_predictions_in_menu();
 7594        let completions_menu_has_precedence = !show_in_menu
 7595            && (self.context_menu.borrow().is_some()
 7596                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7597
 7598        if completions_menu_has_precedence
 7599            || !offset_selection.is_empty()
 7600            || self
 7601                .active_inline_completion
 7602                .as_ref()
 7603                .map_or(false, |completion| {
 7604                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7605                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7606                    !invalidation_range.contains(&offset_selection.head())
 7607                })
 7608        {
 7609            self.discard_inline_completion(false, cx);
 7610            return None;
 7611        }
 7612
 7613        self.take_active_inline_completion(cx);
 7614        let Some(provider) = self.edit_prediction_provider() else {
 7615            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7616            return None;
 7617        };
 7618
 7619        let (buffer, cursor_buffer_position) =
 7620            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7621
 7622        self.edit_prediction_settings =
 7623            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7624
 7625        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7626
 7627        if self.edit_prediction_indent_conflict {
 7628            let cursor_point = cursor.to_point(&multibuffer);
 7629
 7630            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7631
 7632            if let Some((_, indent)) = indents.iter().next() {
 7633                if indent.len == cursor_point.column {
 7634                    self.edit_prediction_indent_conflict = false;
 7635                }
 7636            }
 7637        }
 7638
 7639        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7640        let edits = inline_completion
 7641            .edits
 7642            .into_iter()
 7643            .flat_map(|(range, new_text)| {
 7644                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7645                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7646                Some((start..end, new_text))
 7647            })
 7648            .collect::<Vec<_>>();
 7649        if edits.is_empty() {
 7650            return None;
 7651        }
 7652
 7653        let first_edit_start = edits.first().unwrap().0.start;
 7654        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7655        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7656
 7657        let last_edit_end = edits.last().unwrap().0.end;
 7658        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7659        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7660
 7661        let cursor_row = cursor.to_point(&multibuffer).row;
 7662
 7663        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7664
 7665        let mut inlay_ids = Vec::new();
 7666        let invalidation_row_range;
 7667        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7668            Some(cursor_row..edit_end_row)
 7669        } else if cursor_row > edit_end_row {
 7670            Some(edit_start_row..cursor_row)
 7671        } else {
 7672            None
 7673        };
 7674        let is_move =
 7675            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7676        let completion = if is_move {
 7677            invalidation_row_range =
 7678                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7679            let target = first_edit_start;
 7680            InlineCompletion::Move { target, snapshot }
 7681        } else {
 7682            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7683                && !self.inline_completions_hidden_for_vim_mode;
 7684
 7685            if show_completions_in_buffer {
 7686                if edits
 7687                    .iter()
 7688                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7689                {
 7690                    let mut inlays = Vec::new();
 7691                    for (range, new_text) in &edits {
 7692                        let inlay = Inlay::inline_completion(
 7693                            post_inc(&mut self.next_inlay_id),
 7694                            range.start,
 7695                            new_text.as_str(),
 7696                        );
 7697                        inlay_ids.push(inlay.id);
 7698                        inlays.push(inlay);
 7699                    }
 7700
 7701                    self.splice_inlays(&[], inlays, cx);
 7702                } else {
 7703                    let background_color = cx.theme().status().deleted_background;
 7704                    self.highlight_text::<InlineCompletionHighlight>(
 7705                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7706                        HighlightStyle {
 7707                            background_color: Some(background_color),
 7708                            ..Default::default()
 7709                        },
 7710                        cx,
 7711                    );
 7712                }
 7713            }
 7714
 7715            invalidation_row_range = edit_start_row..edit_end_row;
 7716
 7717            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7718                if provider.show_tab_accept_marker() {
 7719                    EditDisplayMode::TabAccept
 7720                } else {
 7721                    EditDisplayMode::Inline
 7722                }
 7723            } else {
 7724                EditDisplayMode::DiffPopover
 7725            };
 7726
 7727            InlineCompletion::Edit {
 7728                edits,
 7729                edit_preview: inline_completion.edit_preview,
 7730                display_mode,
 7731                snapshot,
 7732            }
 7733        };
 7734
 7735        let invalidation_range = multibuffer
 7736            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7737            ..multibuffer.anchor_after(Point::new(
 7738                invalidation_row_range.end,
 7739                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7740            ));
 7741
 7742        self.stale_inline_completion_in_menu = None;
 7743        self.active_inline_completion = Some(InlineCompletionState {
 7744            inlay_ids,
 7745            completion,
 7746            completion_id: inline_completion.id,
 7747            invalidation_range,
 7748        });
 7749
 7750        cx.notify();
 7751
 7752        Some(())
 7753    }
 7754
 7755    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7756        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7757    }
 7758
 7759    fn clear_tasks(&mut self) {
 7760        self.tasks.clear()
 7761    }
 7762
 7763    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7764        if self.tasks.insert(key, value).is_some() {
 7765            // This case should hopefully be rare, but just in case...
 7766            log::error!(
 7767                "multiple different run targets found on a single line, only the last target will be rendered"
 7768            )
 7769        }
 7770    }
 7771
 7772    /// Get all display points of breakpoints that will be rendered within editor
 7773    ///
 7774    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7775    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7776    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7777    fn active_breakpoints(
 7778        &self,
 7779        range: Range<DisplayRow>,
 7780        window: &mut Window,
 7781        cx: &mut Context<Self>,
 7782    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7783        let mut breakpoint_display_points = HashMap::default();
 7784
 7785        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7786            return breakpoint_display_points;
 7787        };
 7788
 7789        let snapshot = self.snapshot(window, cx);
 7790
 7791        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7792        let Some(project) = self.project.as_ref() else {
 7793            return breakpoint_display_points;
 7794        };
 7795
 7796        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7797            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7798
 7799        for (buffer_snapshot, range, excerpt_id) in
 7800            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7801        {
 7802            let Some(buffer) = project
 7803                .read(cx)
 7804                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7805            else {
 7806                continue;
 7807            };
 7808            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7809                &buffer,
 7810                Some(
 7811                    buffer_snapshot.anchor_before(range.start)
 7812                        ..buffer_snapshot.anchor_after(range.end),
 7813                ),
 7814                buffer_snapshot,
 7815                cx,
 7816            );
 7817            for (breakpoint, state) in breakpoints {
 7818                let multi_buffer_anchor =
 7819                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7820                let position = multi_buffer_anchor
 7821                    .to_point(&multi_buffer_snapshot)
 7822                    .to_display_point(&snapshot);
 7823
 7824                breakpoint_display_points.insert(
 7825                    position.row(),
 7826                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7827                );
 7828            }
 7829        }
 7830
 7831        breakpoint_display_points
 7832    }
 7833
 7834    fn breakpoint_context_menu(
 7835        &self,
 7836        anchor: Anchor,
 7837        window: &mut Window,
 7838        cx: &mut Context<Self>,
 7839    ) -> Entity<ui::ContextMenu> {
 7840        let weak_editor = cx.weak_entity();
 7841        let focus_handle = self.focus_handle(cx);
 7842
 7843        let row = self
 7844            .buffer
 7845            .read(cx)
 7846            .snapshot(cx)
 7847            .summary_for_anchor::<Point>(&anchor)
 7848            .row;
 7849
 7850        let breakpoint = self
 7851            .breakpoint_at_row(row, window, cx)
 7852            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7853
 7854        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7855            "Edit Log Breakpoint"
 7856        } else {
 7857            "Set Log Breakpoint"
 7858        };
 7859
 7860        let condition_breakpoint_msg = if breakpoint
 7861            .as_ref()
 7862            .is_some_and(|bp| bp.1.condition.is_some())
 7863        {
 7864            "Edit Condition Breakpoint"
 7865        } else {
 7866            "Set Condition Breakpoint"
 7867        };
 7868
 7869        let hit_condition_breakpoint_msg = if breakpoint
 7870            .as_ref()
 7871            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7872        {
 7873            "Edit Hit Condition Breakpoint"
 7874        } else {
 7875            "Set Hit Condition Breakpoint"
 7876        };
 7877
 7878        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7879            "Unset Breakpoint"
 7880        } else {
 7881            "Set Breakpoint"
 7882        };
 7883
 7884        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7885
 7886        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7887            BreakpointState::Enabled => Some("Disable"),
 7888            BreakpointState::Disabled => Some("Enable"),
 7889        });
 7890
 7891        let (anchor, breakpoint) =
 7892            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7893
 7894        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7895            menu.on_blur_subscription(Subscription::new(|| {}))
 7896                .context(focus_handle)
 7897                .when(run_to_cursor, |this| {
 7898                    let weak_editor = weak_editor.clone();
 7899                    this.entry("Run to cursor", None, move |window, cx| {
 7900                        weak_editor
 7901                            .update(cx, |editor, cx| {
 7902                                editor.change_selections(
 7903                                    SelectionEffects::no_scroll(),
 7904                                    window,
 7905                                    cx,
 7906                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7907                                );
 7908                            })
 7909                            .ok();
 7910
 7911                        window.dispatch_action(Box::new(RunToCursor), cx);
 7912                    })
 7913                    .separator()
 7914                })
 7915                .when_some(toggle_state_msg, |this, msg| {
 7916                    this.entry(msg, None, {
 7917                        let weak_editor = weak_editor.clone();
 7918                        let breakpoint = breakpoint.clone();
 7919                        move |_window, cx| {
 7920                            weak_editor
 7921                                .update(cx, |this, cx| {
 7922                                    this.edit_breakpoint_at_anchor(
 7923                                        anchor,
 7924                                        breakpoint.as_ref().clone(),
 7925                                        BreakpointEditAction::InvertState,
 7926                                        cx,
 7927                                    );
 7928                                })
 7929                                .log_err();
 7930                        }
 7931                    })
 7932                })
 7933                .entry(set_breakpoint_msg, None, {
 7934                    let weak_editor = weak_editor.clone();
 7935                    let breakpoint = breakpoint.clone();
 7936                    move |_window, cx| {
 7937                        weak_editor
 7938                            .update(cx, |this, cx| {
 7939                                this.edit_breakpoint_at_anchor(
 7940                                    anchor,
 7941                                    breakpoint.as_ref().clone(),
 7942                                    BreakpointEditAction::Toggle,
 7943                                    cx,
 7944                                );
 7945                            })
 7946                            .log_err();
 7947                    }
 7948                })
 7949                .entry(log_breakpoint_msg, None, {
 7950                    let breakpoint = breakpoint.clone();
 7951                    let weak_editor = weak_editor.clone();
 7952                    move |window, cx| {
 7953                        weak_editor
 7954                            .update(cx, |this, cx| {
 7955                                this.add_edit_breakpoint_block(
 7956                                    anchor,
 7957                                    breakpoint.as_ref(),
 7958                                    BreakpointPromptEditAction::Log,
 7959                                    window,
 7960                                    cx,
 7961                                );
 7962                            })
 7963                            .log_err();
 7964                    }
 7965                })
 7966                .entry(condition_breakpoint_msg, None, {
 7967                    let breakpoint = breakpoint.clone();
 7968                    let weak_editor = weak_editor.clone();
 7969                    move |window, cx| {
 7970                        weak_editor
 7971                            .update(cx, |this, cx| {
 7972                                this.add_edit_breakpoint_block(
 7973                                    anchor,
 7974                                    breakpoint.as_ref(),
 7975                                    BreakpointPromptEditAction::Condition,
 7976                                    window,
 7977                                    cx,
 7978                                );
 7979                            })
 7980                            .log_err();
 7981                    }
 7982                })
 7983                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7984                    weak_editor
 7985                        .update(cx, |this, cx| {
 7986                            this.add_edit_breakpoint_block(
 7987                                anchor,
 7988                                breakpoint.as_ref(),
 7989                                BreakpointPromptEditAction::HitCondition,
 7990                                window,
 7991                                cx,
 7992                            );
 7993                        })
 7994                        .log_err();
 7995                })
 7996        })
 7997    }
 7998
 7999    fn render_breakpoint(
 8000        &self,
 8001        position: Anchor,
 8002        row: DisplayRow,
 8003        breakpoint: &Breakpoint,
 8004        state: Option<BreakpointSessionState>,
 8005        cx: &mut Context<Self>,
 8006    ) -> IconButton {
 8007        let is_rejected = state.is_some_and(|s| !s.verified);
 8008        // Is it a breakpoint that shows up when hovering over gutter?
 8009        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8010            (false, false),
 8011            |PhantomBreakpointIndicator {
 8012                 is_active,
 8013                 display_row,
 8014                 collides_with_existing_breakpoint,
 8015             }| {
 8016                (
 8017                    is_active && display_row == row,
 8018                    collides_with_existing_breakpoint,
 8019                )
 8020            },
 8021        );
 8022
 8023        let (color, icon) = {
 8024            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8025                (false, false) => ui::IconName::DebugBreakpoint,
 8026                (true, false) => ui::IconName::DebugLogBreakpoint,
 8027                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8028                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8029            };
 8030
 8031            let color = if is_phantom {
 8032                Color::Hint
 8033            } else if is_rejected {
 8034                Color::Disabled
 8035            } else {
 8036                Color::Debugger
 8037            };
 8038
 8039            (color, icon)
 8040        };
 8041
 8042        let breakpoint = Arc::from(breakpoint.clone());
 8043
 8044        let alt_as_text = gpui::Keystroke {
 8045            modifiers: Modifiers::secondary_key(),
 8046            ..Default::default()
 8047        };
 8048        let primary_action_text = if breakpoint.is_disabled() {
 8049            "Enable breakpoint"
 8050        } else if is_phantom && !collides_with_existing {
 8051            "Set breakpoint"
 8052        } else {
 8053            "Unset breakpoint"
 8054        };
 8055        let focus_handle = self.focus_handle.clone();
 8056
 8057        let meta = if is_rejected {
 8058            SharedString::from("No executable code is associated with this line.")
 8059        } else if collides_with_existing && !breakpoint.is_disabled() {
 8060            SharedString::from(format!(
 8061                "{alt_as_text}-click to disable,\nright-click for more options."
 8062            ))
 8063        } else {
 8064            SharedString::from("Right-click for more options.")
 8065        };
 8066        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8067            .icon_size(IconSize::XSmall)
 8068            .size(ui::ButtonSize::None)
 8069            .when(is_rejected, |this| {
 8070                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8071            })
 8072            .icon_color(color)
 8073            .style(ButtonStyle::Transparent)
 8074            .on_click(cx.listener({
 8075                let breakpoint = breakpoint.clone();
 8076
 8077                move |editor, event: &ClickEvent, window, cx| {
 8078                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8079                        BreakpointEditAction::InvertState
 8080                    } else {
 8081                        BreakpointEditAction::Toggle
 8082                    };
 8083
 8084                    window.focus(&editor.focus_handle(cx));
 8085                    editor.edit_breakpoint_at_anchor(
 8086                        position,
 8087                        breakpoint.as_ref().clone(),
 8088                        edit_action,
 8089                        cx,
 8090                    );
 8091                }
 8092            }))
 8093            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8094                editor.set_breakpoint_context_menu(
 8095                    row,
 8096                    Some(position),
 8097                    event.down.position,
 8098                    window,
 8099                    cx,
 8100                );
 8101            }))
 8102            .tooltip(move |window, cx| {
 8103                Tooltip::with_meta_in(
 8104                    primary_action_text,
 8105                    Some(&ToggleBreakpoint),
 8106                    meta.clone(),
 8107                    &focus_handle,
 8108                    window,
 8109                    cx,
 8110                )
 8111            })
 8112    }
 8113
 8114    fn build_tasks_context(
 8115        project: &Entity<Project>,
 8116        buffer: &Entity<Buffer>,
 8117        buffer_row: u32,
 8118        tasks: &Arc<RunnableTasks>,
 8119        cx: &mut Context<Self>,
 8120    ) -> Task<Option<task::TaskContext>> {
 8121        let position = Point::new(buffer_row, tasks.column);
 8122        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8123        let location = Location {
 8124            buffer: buffer.clone(),
 8125            range: range_start..range_start,
 8126        };
 8127        // Fill in the environmental variables from the tree-sitter captures
 8128        let mut captured_task_variables = TaskVariables::default();
 8129        for (capture_name, value) in tasks.extra_variables.clone() {
 8130            captured_task_variables.insert(
 8131                task::VariableName::Custom(capture_name.into()),
 8132                value.clone(),
 8133            );
 8134        }
 8135        project.update(cx, |project, cx| {
 8136            project.task_store().update(cx, |task_store, cx| {
 8137                task_store.task_context_for_location(captured_task_variables, location, cx)
 8138            })
 8139        })
 8140    }
 8141
 8142    pub fn spawn_nearest_task(
 8143        &mut self,
 8144        action: &SpawnNearestTask,
 8145        window: &mut Window,
 8146        cx: &mut Context<Self>,
 8147    ) {
 8148        let Some((workspace, _)) = self.workspace.clone() else {
 8149            return;
 8150        };
 8151        let Some(project) = self.project.clone() else {
 8152            return;
 8153        };
 8154
 8155        // Try to find a closest, enclosing node using tree-sitter that has a
 8156        // task
 8157        let Some((buffer, buffer_row, tasks)) = self
 8158            .find_enclosing_node_task(cx)
 8159            // Or find the task that's closest in row-distance.
 8160            .or_else(|| self.find_closest_task(cx))
 8161        else {
 8162            return;
 8163        };
 8164
 8165        let reveal_strategy = action.reveal;
 8166        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8167        cx.spawn_in(window, async move |_, cx| {
 8168            let context = task_context.await?;
 8169            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8170
 8171            let resolved = &mut resolved_task.resolved;
 8172            resolved.reveal = reveal_strategy;
 8173
 8174            workspace
 8175                .update_in(cx, |workspace, window, cx| {
 8176                    workspace.schedule_resolved_task(
 8177                        task_source_kind,
 8178                        resolved_task,
 8179                        false,
 8180                        window,
 8181                        cx,
 8182                    );
 8183                })
 8184                .ok()
 8185        })
 8186        .detach();
 8187    }
 8188
 8189    fn find_closest_task(
 8190        &mut self,
 8191        cx: &mut Context<Self>,
 8192    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8193        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8194
 8195        let ((buffer_id, row), tasks) = self
 8196            .tasks
 8197            .iter()
 8198            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8199
 8200        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8201        let tasks = Arc::new(tasks.to_owned());
 8202        Some((buffer, *row, tasks))
 8203    }
 8204
 8205    fn find_enclosing_node_task(
 8206        &mut self,
 8207        cx: &mut Context<Self>,
 8208    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8209        let snapshot = self.buffer.read(cx).snapshot(cx);
 8210        let offset = self.selections.newest::<usize>(cx).head();
 8211        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8212        let buffer_id = excerpt.buffer().remote_id();
 8213
 8214        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8215        let mut cursor = layer.node().walk();
 8216
 8217        while cursor.goto_first_child_for_byte(offset).is_some() {
 8218            if cursor.node().end_byte() == offset {
 8219                cursor.goto_next_sibling();
 8220            }
 8221        }
 8222
 8223        // Ascend to the smallest ancestor that contains the range and has a task.
 8224        loop {
 8225            let node = cursor.node();
 8226            let node_range = node.byte_range();
 8227            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8228
 8229            // Check if this node contains our offset
 8230            if node_range.start <= offset && node_range.end >= offset {
 8231                // If it contains offset, check for task
 8232                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8233                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8234                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8235                }
 8236            }
 8237
 8238            if !cursor.goto_parent() {
 8239                break;
 8240            }
 8241        }
 8242        None
 8243    }
 8244
 8245    fn render_run_indicator(
 8246        &self,
 8247        _style: &EditorStyle,
 8248        is_active: bool,
 8249        row: DisplayRow,
 8250        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8251        cx: &mut Context<Self>,
 8252    ) -> IconButton {
 8253        let color = Color::Muted;
 8254        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8255
 8256        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8257            .shape(ui::IconButtonShape::Square)
 8258            .icon_size(IconSize::XSmall)
 8259            .icon_color(color)
 8260            .toggle_state(is_active)
 8261            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8262                let quick_launch = e.down.button == MouseButton::Left;
 8263                window.focus(&editor.focus_handle(cx));
 8264                editor.toggle_code_actions(
 8265                    &ToggleCodeActions {
 8266                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8267                        quick_launch,
 8268                    },
 8269                    window,
 8270                    cx,
 8271                );
 8272            }))
 8273            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8274                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8275            }))
 8276    }
 8277
 8278    pub fn context_menu_visible(&self) -> bool {
 8279        !self.edit_prediction_preview_is_active()
 8280            && self
 8281                .context_menu
 8282                .borrow()
 8283                .as_ref()
 8284                .map_or(false, |menu| menu.visible())
 8285    }
 8286
 8287    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8288        self.context_menu
 8289            .borrow()
 8290            .as_ref()
 8291            .map(|menu| menu.origin())
 8292    }
 8293
 8294    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8295        self.context_menu_options = Some(options);
 8296    }
 8297
 8298    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8299    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8300
 8301    fn render_edit_prediction_popover(
 8302        &mut self,
 8303        text_bounds: &Bounds<Pixels>,
 8304        content_origin: gpui::Point<Pixels>,
 8305        right_margin: Pixels,
 8306        editor_snapshot: &EditorSnapshot,
 8307        visible_row_range: Range<DisplayRow>,
 8308        scroll_top: f32,
 8309        scroll_bottom: f32,
 8310        line_layouts: &[LineWithInvisibles],
 8311        line_height: Pixels,
 8312        scroll_pixel_position: gpui::Point<Pixels>,
 8313        newest_selection_head: Option<DisplayPoint>,
 8314        editor_width: Pixels,
 8315        style: &EditorStyle,
 8316        window: &mut Window,
 8317        cx: &mut App,
 8318    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8319        if self.mode().is_minimap() {
 8320            return None;
 8321        }
 8322        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8323
 8324        if self.edit_prediction_visible_in_cursor_popover(true) {
 8325            return None;
 8326        }
 8327
 8328        match &active_inline_completion.completion {
 8329            InlineCompletion::Move { target, .. } => {
 8330                let target_display_point = target.to_display_point(editor_snapshot);
 8331
 8332                if self.edit_prediction_requires_modifier() {
 8333                    if !self.edit_prediction_preview_is_active() {
 8334                        return None;
 8335                    }
 8336
 8337                    self.render_edit_prediction_modifier_jump_popover(
 8338                        text_bounds,
 8339                        content_origin,
 8340                        visible_row_range,
 8341                        line_layouts,
 8342                        line_height,
 8343                        scroll_pixel_position,
 8344                        newest_selection_head,
 8345                        target_display_point,
 8346                        window,
 8347                        cx,
 8348                    )
 8349                } else {
 8350                    self.render_edit_prediction_eager_jump_popover(
 8351                        text_bounds,
 8352                        content_origin,
 8353                        editor_snapshot,
 8354                        visible_row_range,
 8355                        scroll_top,
 8356                        scroll_bottom,
 8357                        line_height,
 8358                        scroll_pixel_position,
 8359                        target_display_point,
 8360                        editor_width,
 8361                        window,
 8362                        cx,
 8363                    )
 8364                }
 8365            }
 8366            InlineCompletion::Edit {
 8367                display_mode: EditDisplayMode::Inline,
 8368                ..
 8369            } => None,
 8370            InlineCompletion::Edit {
 8371                display_mode: EditDisplayMode::TabAccept,
 8372                edits,
 8373                ..
 8374            } => {
 8375                let range = &edits.first()?.0;
 8376                let target_display_point = range.end.to_display_point(editor_snapshot);
 8377
 8378                self.render_edit_prediction_end_of_line_popover(
 8379                    "Accept",
 8380                    editor_snapshot,
 8381                    visible_row_range,
 8382                    target_display_point,
 8383                    line_height,
 8384                    scroll_pixel_position,
 8385                    content_origin,
 8386                    editor_width,
 8387                    window,
 8388                    cx,
 8389                )
 8390            }
 8391            InlineCompletion::Edit {
 8392                edits,
 8393                edit_preview,
 8394                display_mode: EditDisplayMode::DiffPopover,
 8395                snapshot,
 8396            } => self.render_edit_prediction_diff_popover(
 8397                text_bounds,
 8398                content_origin,
 8399                right_margin,
 8400                editor_snapshot,
 8401                visible_row_range,
 8402                line_layouts,
 8403                line_height,
 8404                scroll_pixel_position,
 8405                newest_selection_head,
 8406                editor_width,
 8407                style,
 8408                edits,
 8409                edit_preview,
 8410                snapshot,
 8411                window,
 8412                cx,
 8413            ),
 8414        }
 8415    }
 8416
 8417    fn render_edit_prediction_modifier_jump_popover(
 8418        &mut self,
 8419        text_bounds: &Bounds<Pixels>,
 8420        content_origin: gpui::Point<Pixels>,
 8421        visible_row_range: Range<DisplayRow>,
 8422        line_layouts: &[LineWithInvisibles],
 8423        line_height: Pixels,
 8424        scroll_pixel_position: gpui::Point<Pixels>,
 8425        newest_selection_head: Option<DisplayPoint>,
 8426        target_display_point: DisplayPoint,
 8427        window: &mut Window,
 8428        cx: &mut App,
 8429    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8430        let scrolled_content_origin =
 8431            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8432
 8433        const SCROLL_PADDING_Y: Pixels = px(12.);
 8434
 8435        if target_display_point.row() < visible_row_range.start {
 8436            return self.render_edit_prediction_scroll_popover(
 8437                |_| SCROLL_PADDING_Y,
 8438                IconName::ArrowUp,
 8439                visible_row_range,
 8440                line_layouts,
 8441                newest_selection_head,
 8442                scrolled_content_origin,
 8443                window,
 8444                cx,
 8445            );
 8446        } else if target_display_point.row() >= visible_row_range.end {
 8447            return self.render_edit_prediction_scroll_popover(
 8448                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8449                IconName::ArrowDown,
 8450                visible_row_range,
 8451                line_layouts,
 8452                newest_selection_head,
 8453                scrolled_content_origin,
 8454                window,
 8455                cx,
 8456            );
 8457        }
 8458
 8459        const POLE_WIDTH: Pixels = px(2.);
 8460
 8461        let line_layout =
 8462            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8463        let target_column = target_display_point.column() as usize;
 8464
 8465        let target_x = line_layout.x_for_index(target_column);
 8466        let target_y =
 8467            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8468
 8469        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8470
 8471        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8472        border_color.l += 0.001;
 8473
 8474        let mut element = v_flex()
 8475            .items_end()
 8476            .when(flag_on_right, |el| el.items_start())
 8477            .child(if flag_on_right {
 8478                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8479                    .rounded_bl(px(0.))
 8480                    .rounded_tl(px(0.))
 8481                    .border_l_2()
 8482                    .border_color(border_color)
 8483            } else {
 8484                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8485                    .rounded_br(px(0.))
 8486                    .rounded_tr(px(0.))
 8487                    .border_r_2()
 8488                    .border_color(border_color)
 8489            })
 8490            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8491            .into_any();
 8492
 8493        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8494
 8495        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8496            - point(
 8497                if flag_on_right {
 8498                    POLE_WIDTH
 8499                } else {
 8500                    size.width - POLE_WIDTH
 8501                },
 8502                size.height - line_height,
 8503            );
 8504
 8505        origin.x = origin.x.max(content_origin.x);
 8506
 8507        element.prepaint_at(origin, window, cx);
 8508
 8509        Some((element, origin))
 8510    }
 8511
 8512    fn render_edit_prediction_scroll_popover(
 8513        &mut self,
 8514        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8515        scroll_icon: IconName,
 8516        visible_row_range: Range<DisplayRow>,
 8517        line_layouts: &[LineWithInvisibles],
 8518        newest_selection_head: Option<DisplayPoint>,
 8519        scrolled_content_origin: gpui::Point<Pixels>,
 8520        window: &mut Window,
 8521        cx: &mut App,
 8522    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8523        let mut element = self
 8524            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8525            .into_any();
 8526
 8527        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8528
 8529        let cursor = newest_selection_head?;
 8530        let cursor_row_layout =
 8531            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8532        let cursor_column = cursor.column() as usize;
 8533
 8534        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8535
 8536        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8537
 8538        element.prepaint_at(origin, window, cx);
 8539        Some((element, origin))
 8540    }
 8541
 8542    fn render_edit_prediction_eager_jump_popover(
 8543        &mut self,
 8544        text_bounds: &Bounds<Pixels>,
 8545        content_origin: gpui::Point<Pixels>,
 8546        editor_snapshot: &EditorSnapshot,
 8547        visible_row_range: Range<DisplayRow>,
 8548        scroll_top: f32,
 8549        scroll_bottom: f32,
 8550        line_height: Pixels,
 8551        scroll_pixel_position: gpui::Point<Pixels>,
 8552        target_display_point: DisplayPoint,
 8553        editor_width: Pixels,
 8554        window: &mut Window,
 8555        cx: &mut App,
 8556    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8557        if target_display_point.row().as_f32() < scroll_top {
 8558            let mut element = self
 8559                .render_edit_prediction_line_popover(
 8560                    "Jump to Edit",
 8561                    Some(IconName::ArrowUp),
 8562                    window,
 8563                    cx,
 8564                )?
 8565                .into_any();
 8566
 8567            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8568            let offset = point(
 8569                (text_bounds.size.width - size.width) / 2.,
 8570                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8571            );
 8572
 8573            let origin = text_bounds.origin + offset;
 8574            element.prepaint_at(origin, window, cx);
 8575            Some((element, origin))
 8576        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8577            let mut element = self
 8578                .render_edit_prediction_line_popover(
 8579                    "Jump to Edit",
 8580                    Some(IconName::ArrowDown),
 8581                    window,
 8582                    cx,
 8583                )?
 8584                .into_any();
 8585
 8586            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8587            let offset = point(
 8588                (text_bounds.size.width - size.width) / 2.,
 8589                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8590            );
 8591
 8592            let origin = text_bounds.origin + offset;
 8593            element.prepaint_at(origin, window, cx);
 8594            Some((element, origin))
 8595        } else {
 8596            self.render_edit_prediction_end_of_line_popover(
 8597                "Jump to Edit",
 8598                editor_snapshot,
 8599                visible_row_range,
 8600                target_display_point,
 8601                line_height,
 8602                scroll_pixel_position,
 8603                content_origin,
 8604                editor_width,
 8605                window,
 8606                cx,
 8607            )
 8608        }
 8609    }
 8610
 8611    fn render_edit_prediction_end_of_line_popover(
 8612        self: &mut Editor,
 8613        label: &'static str,
 8614        editor_snapshot: &EditorSnapshot,
 8615        visible_row_range: Range<DisplayRow>,
 8616        target_display_point: DisplayPoint,
 8617        line_height: Pixels,
 8618        scroll_pixel_position: gpui::Point<Pixels>,
 8619        content_origin: gpui::Point<Pixels>,
 8620        editor_width: Pixels,
 8621        window: &mut Window,
 8622        cx: &mut App,
 8623    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8624        let target_line_end = DisplayPoint::new(
 8625            target_display_point.row(),
 8626            editor_snapshot.line_len(target_display_point.row()),
 8627        );
 8628
 8629        let mut element = self
 8630            .render_edit_prediction_line_popover(label, None, window, cx)?
 8631            .into_any();
 8632
 8633        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8634
 8635        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8636
 8637        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8638        let mut origin = start_point
 8639            + line_origin
 8640            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8641        origin.x = origin.x.max(content_origin.x);
 8642
 8643        let max_x = content_origin.x + editor_width - size.width;
 8644
 8645        if origin.x > max_x {
 8646            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8647
 8648            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8649                origin.y += offset;
 8650                IconName::ArrowUp
 8651            } else {
 8652                origin.y -= offset;
 8653                IconName::ArrowDown
 8654            };
 8655
 8656            element = self
 8657                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8658                .into_any();
 8659
 8660            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8661
 8662            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8663        }
 8664
 8665        element.prepaint_at(origin, window, cx);
 8666        Some((element, origin))
 8667    }
 8668
 8669    fn render_edit_prediction_diff_popover(
 8670        self: &Editor,
 8671        text_bounds: &Bounds<Pixels>,
 8672        content_origin: gpui::Point<Pixels>,
 8673        right_margin: Pixels,
 8674        editor_snapshot: &EditorSnapshot,
 8675        visible_row_range: Range<DisplayRow>,
 8676        line_layouts: &[LineWithInvisibles],
 8677        line_height: Pixels,
 8678        scroll_pixel_position: gpui::Point<Pixels>,
 8679        newest_selection_head: Option<DisplayPoint>,
 8680        editor_width: Pixels,
 8681        style: &EditorStyle,
 8682        edits: &Vec<(Range<Anchor>, String)>,
 8683        edit_preview: &Option<language::EditPreview>,
 8684        snapshot: &language::BufferSnapshot,
 8685        window: &mut Window,
 8686        cx: &mut App,
 8687    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8688        let edit_start = edits
 8689            .first()
 8690            .unwrap()
 8691            .0
 8692            .start
 8693            .to_display_point(editor_snapshot);
 8694        let edit_end = edits
 8695            .last()
 8696            .unwrap()
 8697            .0
 8698            .end
 8699            .to_display_point(editor_snapshot);
 8700
 8701        let is_visible = visible_row_range.contains(&edit_start.row())
 8702            || visible_row_range.contains(&edit_end.row());
 8703        if !is_visible {
 8704            return None;
 8705        }
 8706
 8707        let highlighted_edits =
 8708            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8709
 8710        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8711        let line_count = highlighted_edits.text.lines().count();
 8712
 8713        const BORDER_WIDTH: Pixels = px(1.);
 8714
 8715        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8716        let has_keybind = keybind.is_some();
 8717
 8718        let mut element = h_flex()
 8719            .items_start()
 8720            .child(
 8721                h_flex()
 8722                    .bg(cx.theme().colors().editor_background)
 8723                    .border(BORDER_WIDTH)
 8724                    .shadow_xs()
 8725                    .border_color(cx.theme().colors().border)
 8726                    .rounded_l_lg()
 8727                    .when(line_count > 1, |el| el.rounded_br_lg())
 8728                    .pr_1()
 8729                    .child(styled_text),
 8730            )
 8731            .child(
 8732                h_flex()
 8733                    .h(line_height + BORDER_WIDTH * 2.)
 8734                    .px_1p5()
 8735                    .gap_1()
 8736                    // Workaround: For some reason, there's a gap if we don't do this
 8737                    .ml(-BORDER_WIDTH)
 8738                    .shadow(vec![gpui::BoxShadow {
 8739                        color: gpui::black().opacity(0.05),
 8740                        offset: point(px(1.), px(1.)),
 8741                        blur_radius: px(2.),
 8742                        spread_radius: px(0.),
 8743                    }])
 8744                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8745                    .border(BORDER_WIDTH)
 8746                    .border_color(cx.theme().colors().border)
 8747                    .rounded_r_lg()
 8748                    .id("edit_prediction_diff_popover_keybind")
 8749                    .when(!has_keybind, |el| {
 8750                        let status_colors = cx.theme().status();
 8751
 8752                        el.bg(status_colors.error_background)
 8753                            .border_color(status_colors.error.opacity(0.6))
 8754                            .child(Icon::new(IconName::Info).color(Color::Error))
 8755                            .cursor_default()
 8756                            .hoverable_tooltip(move |_window, cx| {
 8757                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8758                            })
 8759                    })
 8760                    .children(keybind),
 8761            )
 8762            .into_any();
 8763
 8764        let longest_row =
 8765            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8766        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8767            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8768        } else {
 8769            layout_line(
 8770                longest_row,
 8771                editor_snapshot,
 8772                style,
 8773                editor_width,
 8774                |_| false,
 8775                window,
 8776                cx,
 8777            )
 8778            .width
 8779        };
 8780
 8781        let viewport_bounds =
 8782            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8783                right: -right_margin,
 8784                ..Default::default()
 8785            });
 8786
 8787        let x_after_longest =
 8788            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8789                - scroll_pixel_position.x;
 8790
 8791        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8792
 8793        // Fully visible if it can be displayed within the window (allow overlapping other
 8794        // panes). However, this is only allowed if the popover starts within text_bounds.
 8795        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8796            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8797
 8798        let mut origin = if can_position_to_the_right {
 8799            point(
 8800                x_after_longest,
 8801                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8802                    - scroll_pixel_position.y,
 8803            )
 8804        } else {
 8805            let cursor_row = newest_selection_head.map(|head| head.row());
 8806            let above_edit = edit_start
 8807                .row()
 8808                .0
 8809                .checked_sub(line_count as u32)
 8810                .map(DisplayRow);
 8811            let below_edit = Some(edit_end.row() + 1);
 8812            let above_cursor =
 8813                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8814            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8815
 8816            // Place the edit popover adjacent to the edit if there is a location
 8817            // available that is onscreen and does not obscure the cursor. Otherwise,
 8818            // place it adjacent to the cursor.
 8819            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8820                .into_iter()
 8821                .flatten()
 8822                .find(|&start_row| {
 8823                    let end_row = start_row + line_count as u32;
 8824                    visible_row_range.contains(&start_row)
 8825                        && visible_row_range.contains(&end_row)
 8826                        && cursor_row.map_or(true, |cursor_row| {
 8827                            !((start_row..end_row).contains(&cursor_row))
 8828                        })
 8829                })?;
 8830
 8831            content_origin
 8832                + point(
 8833                    -scroll_pixel_position.x,
 8834                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8835                )
 8836        };
 8837
 8838        origin.x -= BORDER_WIDTH;
 8839
 8840        window.defer_draw(element, origin, 1);
 8841
 8842        // Do not return an element, since it will already be drawn due to defer_draw.
 8843        None
 8844    }
 8845
 8846    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8847        px(30.)
 8848    }
 8849
 8850    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8851        if self.read_only(cx) {
 8852            cx.theme().players().read_only()
 8853        } else {
 8854            self.style.as_ref().unwrap().local_player
 8855        }
 8856    }
 8857
 8858    fn render_edit_prediction_accept_keybind(
 8859        &self,
 8860        window: &mut Window,
 8861        cx: &App,
 8862    ) -> Option<AnyElement> {
 8863        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8864        let accept_keystroke = accept_binding.keystroke()?;
 8865
 8866        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8867
 8868        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8869            Color::Accent
 8870        } else {
 8871            Color::Muted
 8872        };
 8873
 8874        h_flex()
 8875            .px_0p5()
 8876            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8877            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8878            .text_size(TextSize::XSmall.rems(cx))
 8879            .child(h_flex().children(ui::render_modifiers(
 8880                &accept_keystroke.modifiers,
 8881                PlatformStyle::platform(),
 8882                Some(modifiers_color),
 8883                Some(IconSize::XSmall.rems().into()),
 8884                true,
 8885            )))
 8886            .when(is_platform_style_mac, |parent| {
 8887                parent.child(accept_keystroke.key.clone())
 8888            })
 8889            .when(!is_platform_style_mac, |parent| {
 8890                parent.child(
 8891                    Key::new(
 8892                        util::capitalize(&accept_keystroke.key),
 8893                        Some(Color::Default),
 8894                    )
 8895                    .size(Some(IconSize::XSmall.rems().into())),
 8896                )
 8897            })
 8898            .into_any()
 8899            .into()
 8900    }
 8901
 8902    fn render_edit_prediction_line_popover(
 8903        &self,
 8904        label: impl Into<SharedString>,
 8905        icon: Option<IconName>,
 8906        window: &mut Window,
 8907        cx: &App,
 8908    ) -> Option<Stateful<Div>> {
 8909        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8910
 8911        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8912        let has_keybind = keybind.is_some();
 8913
 8914        let result = h_flex()
 8915            .id("ep-line-popover")
 8916            .py_0p5()
 8917            .pl_1()
 8918            .pr(padding_right)
 8919            .gap_1()
 8920            .rounded_md()
 8921            .border_1()
 8922            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8923            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8924            .shadow_xs()
 8925            .when(!has_keybind, |el| {
 8926                let status_colors = cx.theme().status();
 8927
 8928                el.bg(status_colors.error_background)
 8929                    .border_color(status_colors.error.opacity(0.6))
 8930                    .pl_2()
 8931                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8932                    .cursor_default()
 8933                    .hoverable_tooltip(move |_window, cx| {
 8934                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8935                    })
 8936            })
 8937            .children(keybind)
 8938            .child(
 8939                Label::new(label)
 8940                    .size(LabelSize::Small)
 8941                    .when(!has_keybind, |el| {
 8942                        el.color(cx.theme().status().error.into()).strikethrough()
 8943                    }),
 8944            )
 8945            .when(!has_keybind, |el| {
 8946                el.child(
 8947                    h_flex().ml_1().child(
 8948                        Icon::new(IconName::Info)
 8949                            .size(IconSize::Small)
 8950                            .color(cx.theme().status().error.into()),
 8951                    ),
 8952                )
 8953            })
 8954            .when_some(icon, |element, icon| {
 8955                element.child(
 8956                    div()
 8957                        .mt(px(1.5))
 8958                        .child(Icon::new(icon).size(IconSize::Small)),
 8959                )
 8960            });
 8961
 8962        Some(result)
 8963    }
 8964
 8965    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8966        let accent_color = cx.theme().colors().text_accent;
 8967        let editor_bg_color = cx.theme().colors().editor_background;
 8968        editor_bg_color.blend(accent_color.opacity(0.1))
 8969    }
 8970
 8971    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8972        let accent_color = cx.theme().colors().text_accent;
 8973        let editor_bg_color = cx.theme().colors().editor_background;
 8974        editor_bg_color.blend(accent_color.opacity(0.6))
 8975    }
 8976
 8977    fn render_edit_prediction_cursor_popover(
 8978        &self,
 8979        min_width: Pixels,
 8980        max_width: Pixels,
 8981        cursor_point: Point,
 8982        style: &EditorStyle,
 8983        accept_keystroke: Option<&gpui::Keystroke>,
 8984        _window: &Window,
 8985        cx: &mut Context<Editor>,
 8986    ) -> Option<AnyElement> {
 8987        let provider = self.edit_prediction_provider.as_ref()?;
 8988
 8989        if provider.provider.needs_terms_acceptance(cx) {
 8990            return Some(
 8991                h_flex()
 8992                    .min_w(min_width)
 8993                    .flex_1()
 8994                    .px_2()
 8995                    .py_1()
 8996                    .gap_3()
 8997                    .elevation_2(cx)
 8998                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8999                    .id("accept-terms")
 9000                    .cursor_pointer()
 9001                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9002                    .on_click(cx.listener(|this, _event, window, cx| {
 9003                        cx.stop_propagation();
 9004                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9005                        window.dispatch_action(
 9006                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9007                            cx,
 9008                        );
 9009                    }))
 9010                    .child(
 9011                        h_flex()
 9012                            .flex_1()
 9013                            .gap_2()
 9014                            .child(Icon::new(IconName::ZedPredict))
 9015                            .child(Label::new("Accept Terms of Service"))
 9016                            .child(div().w_full())
 9017                            .child(
 9018                                Icon::new(IconName::ArrowUpRight)
 9019                                    .color(Color::Muted)
 9020                                    .size(IconSize::Small),
 9021                            )
 9022                            .into_any_element(),
 9023                    )
 9024                    .into_any(),
 9025            );
 9026        }
 9027
 9028        let is_refreshing = provider.provider.is_refreshing(cx);
 9029
 9030        fn pending_completion_container() -> Div {
 9031            h_flex()
 9032                .h_full()
 9033                .flex_1()
 9034                .gap_2()
 9035                .child(Icon::new(IconName::ZedPredict))
 9036        }
 9037
 9038        let completion = match &self.active_inline_completion {
 9039            Some(prediction) => {
 9040                if !self.has_visible_completions_menu() {
 9041                    const RADIUS: Pixels = px(6.);
 9042                    const BORDER_WIDTH: Pixels = px(1.);
 9043
 9044                    return Some(
 9045                        h_flex()
 9046                            .elevation_2(cx)
 9047                            .border(BORDER_WIDTH)
 9048                            .border_color(cx.theme().colors().border)
 9049                            .when(accept_keystroke.is_none(), |el| {
 9050                                el.border_color(cx.theme().status().error)
 9051                            })
 9052                            .rounded(RADIUS)
 9053                            .rounded_tl(px(0.))
 9054                            .overflow_hidden()
 9055                            .child(div().px_1p5().child(match &prediction.completion {
 9056                                InlineCompletion::Move { target, snapshot } => {
 9057                                    use text::ToPoint as _;
 9058                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9059                                    {
 9060                                        Icon::new(IconName::ZedPredictDown)
 9061                                    } else {
 9062                                        Icon::new(IconName::ZedPredictUp)
 9063                                    }
 9064                                }
 9065                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9066                            }))
 9067                            .child(
 9068                                h_flex()
 9069                                    .gap_1()
 9070                                    .py_1()
 9071                                    .px_2()
 9072                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9073                                    .border_l_1()
 9074                                    .border_color(cx.theme().colors().border)
 9075                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9076                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9077                                        el.child(
 9078                                            Label::new("Hold")
 9079                                                .size(LabelSize::Small)
 9080                                                .when(accept_keystroke.is_none(), |el| {
 9081                                                    el.strikethrough()
 9082                                                })
 9083                                                .line_height_style(LineHeightStyle::UiLabel),
 9084                                        )
 9085                                    })
 9086                                    .id("edit_prediction_cursor_popover_keybind")
 9087                                    .when(accept_keystroke.is_none(), |el| {
 9088                                        let status_colors = cx.theme().status();
 9089
 9090                                        el.bg(status_colors.error_background)
 9091                                            .border_color(status_colors.error.opacity(0.6))
 9092                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9093                                            .cursor_default()
 9094                                            .hoverable_tooltip(move |_window, cx| {
 9095                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9096                                                    .into()
 9097                                            })
 9098                                    })
 9099                                    .when_some(
 9100                                        accept_keystroke.as_ref(),
 9101                                        |el, accept_keystroke| {
 9102                                            el.child(h_flex().children(ui::render_modifiers(
 9103                                                &accept_keystroke.modifiers,
 9104                                                PlatformStyle::platform(),
 9105                                                Some(Color::Default),
 9106                                                Some(IconSize::XSmall.rems().into()),
 9107                                                false,
 9108                                            )))
 9109                                        },
 9110                                    ),
 9111                            )
 9112                            .into_any(),
 9113                    );
 9114                }
 9115
 9116                self.render_edit_prediction_cursor_popover_preview(
 9117                    prediction,
 9118                    cursor_point,
 9119                    style,
 9120                    cx,
 9121                )?
 9122            }
 9123
 9124            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9125                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9126                    stale_completion,
 9127                    cursor_point,
 9128                    style,
 9129                    cx,
 9130                )?,
 9131
 9132                None => {
 9133                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9134                }
 9135            },
 9136
 9137            None => pending_completion_container().child(Label::new("No Prediction")),
 9138        };
 9139
 9140        let completion = if is_refreshing {
 9141            completion
 9142                .with_animation(
 9143                    "loading-completion",
 9144                    Animation::new(Duration::from_secs(2))
 9145                        .repeat()
 9146                        .with_easing(pulsating_between(0.4, 0.8)),
 9147                    |label, delta| label.opacity(delta),
 9148                )
 9149                .into_any_element()
 9150        } else {
 9151            completion.into_any_element()
 9152        };
 9153
 9154        let has_completion = self.active_inline_completion.is_some();
 9155
 9156        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9157        Some(
 9158            h_flex()
 9159                .min_w(min_width)
 9160                .max_w(max_width)
 9161                .flex_1()
 9162                .elevation_2(cx)
 9163                .border_color(cx.theme().colors().border)
 9164                .child(
 9165                    div()
 9166                        .flex_1()
 9167                        .py_1()
 9168                        .px_2()
 9169                        .overflow_hidden()
 9170                        .child(completion),
 9171                )
 9172                .when_some(accept_keystroke, |el, accept_keystroke| {
 9173                    if !accept_keystroke.modifiers.modified() {
 9174                        return el;
 9175                    }
 9176
 9177                    el.child(
 9178                        h_flex()
 9179                            .h_full()
 9180                            .border_l_1()
 9181                            .rounded_r_lg()
 9182                            .border_color(cx.theme().colors().border)
 9183                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9184                            .gap_1()
 9185                            .py_1()
 9186                            .px_2()
 9187                            .child(
 9188                                h_flex()
 9189                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9190                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9191                                    .child(h_flex().children(ui::render_modifiers(
 9192                                        &accept_keystroke.modifiers,
 9193                                        PlatformStyle::platform(),
 9194                                        Some(if !has_completion {
 9195                                            Color::Muted
 9196                                        } else {
 9197                                            Color::Default
 9198                                        }),
 9199                                        None,
 9200                                        false,
 9201                                    ))),
 9202                            )
 9203                            .child(Label::new("Preview").into_any_element())
 9204                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9205                    )
 9206                })
 9207                .into_any(),
 9208        )
 9209    }
 9210
 9211    fn render_edit_prediction_cursor_popover_preview(
 9212        &self,
 9213        completion: &InlineCompletionState,
 9214        cursor_point: Point,
 9215        style: &EditorStyle,
 9216        cx: &mut Context<Editor>,
 9217    ) -> Option<Div> {
 9218        use text::ToPoint as _;
 9219
 9220        fn render_relative_row_jump(
 9221            prefix: impl Into<String>,
 9222            current_row: u32,
 9223            target_row: u32,
 9224        ) -> Div {
 9225            let (row_diff, arrow) = if target_row < current_row {
 9226                (current_row - target_row, IconName::ArrowUp)
 9227            } else {
 9228                (target_row - current_row, IconName::ArrowDown)
 9229            };
 9230
 9231            h_flex()
 9232                .child(
 9233                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9234                        .color(Color::Muted)
 9235                        .size(LabelSize::Small),
 9236                )
 9237                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9238        }
 9239
 9240        match &completion.completion {
 9241            InlineCompletion::Move {
 9242                target, snapshot, ..
 9243            } => Some(
 9244                h_flex()
 9245                    .px_2()
 9246                    .gap_2()
 9247                    .flex_1()
 9248                    .child(
 9249                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9250                            Icon::new(IconName::ZedPredictDown)
 9251                        } else {
 9252                            Icon::new(IconName::ZedPredictUp)
 9253                        },
 9254                    )
 9255                    .child(Label::new("Jump to Edit")),
 9256            ),
 9257
 9258            InlineCompletion::Edit {
 9259                edits,
 9260                edit_preview,
 9261                snapshot,
 9262                display_mode: _,
 9263            } => {
 9264                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9265
 9266                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9267                    &snapshot,
 9268                    &edits,
 9269                    edit_preview.as_ref()?,
 9270                    true,
 9271                    cx,
 9272                )
 9273                .first_line_preview();
 9274
 9275                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9276                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9277
 9278                let preview = h_flex()
 9279                    .gap_1()
 9280                    .min_w_16()
 9281                    .child(styled_text)
 9282                    .when(has_more_lines, |parent| parent.child(""));
 9283
 9284                let left = if first_edit_row != cursor_point.row {
 9285                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9286                        .into_any_element()
 9287                } else {
 9288                    Icon::new(IconName::ZedPredict).into_any_element()
 9289                };
 9290
 9291                Some(
 9292                    h_flex()
 9293                        .h_full()
 9294                        .flex_1()
 9295                        .gap_2()
 9296                        .pr_1()
 9297                        .overflow_x_hidden()
 9298                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9299                        .child(left)
 9300                        .child(preview),
 9301                )
 9302            }
 9303        }
 9304    }
 9305
 9306    pub fn render_context_menu(
 9307        &self,
 9308        style: &EditorStyle,
 9309        max_height_in_lines: u32,
 9310        window: &mut Window,
 9311        cx: &mut Context<Editor>,
 9312    ) -> Option<AnyElement> {
 9313        let menu = self.context_menu.borrow();
 9314        let menu = menu.as_ref()?;
 9315        if !menu.visible() {
 9316            return None;
 9317        };
 9318        Some(menu.render(style, max_height_in_lines, window, cx))
 9319    }
 9320
 9321    fn render_context_menu_aside(
 9322        &mut self,
 9323        max_size: Size<Pixels>,
 9324        window: &mut Window,
 9325        cx: &mut Context<Editor>,
 9326    ) -> Option<AnyElement> {
 9327        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9328            if menu.visible() {
 9329                menu.render_aside(max_size, window, cx)
 9330            } else {
 9331                None
 9332            }
 9333        })
 9334    }
 9335
 9336    fn hide_context_menu(
 9337        &mut self,
 9338        window: &mut Window,
 9339        cx: &mut Context<Self>,
 9340    ) -> Option<CodeContextMenu> {
 9341        cx.notify();
 9342        self.completion_tasks.clear();
 9343        let context_menu = self.context_menu.borrow_mut().take();
 9344        self.stale_inline_completion_in_menu.take();
 9345        self.update_visible_inline_completion(window, cx);
 9346        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9347            if let Some(completion_provider) = &self.completion_provider {
 9348                completion_provider.selection_changed(None, window, cx);
 9349            }
 9350        }
 9351        context_menu
 9352    }
 9353
 9354    fn show_snippet_choices(
 9355        &mut self,
 9356        choices: &Vec<String>,
 9357        selection: Range<Anchor>,
 9358        cx: &mut Context<Self>,
 9359    ) {
 9360        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9361            (Some(a), Some(b)) if a == b => a,
 9362            _ => {
 9363                log::error!("expected anchor range to have matching buffer IDs");
 9364                return;
 9365            }
 9366        };
 9367        let multi_buffer = self.buffer().read(cx);
 9368        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9369            return;
 9370        };
 9371
 9372        let id = post_inc(&mut self.next_completion_id);
 9373        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9374        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9375            CompletionsMenu::new_snippet_choices(
 9376                id,
 9377                true,
 9378                choices,
 9379                selection,
 9380                buffer,
 9381                snippet_sort_order,
 9382            ),
 9383        ));
 9384    }
 9385
 9386    pub fn insert_snippet(
 9387        &mut self,
 9388        insertion_ranges: &[Range<usize>],
 9389        snippet: Snippet,
 9390        window: &mut Window,
 9391        cx: &mut Context<Self>,
 9392    ) -> Result<()> {
 9393        struct Tabstop<T> {
 9394            is_end_tabstop: bool,
 9395            ranges: Vec<Range<T>>,
 9396            choices: Option<Vec<String>>,
 9397        }
 9398
 9399        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9400            let snippet_text: Arc<str> = snippet.text.clone().into();
 9401            let edits = insertion_ranges
 9402                .iter()
 9403                .cloned()
 9404                .map(|range| (range, snippet_text.clone()));
 9405            let autoindent_mode = AutoindentMode::Block {
 9406                original_indent_columns: Vec::new(),
 9407            };
 9408            buffer.edit(edits, Some(autoindent_mode), cx);
 9409
 9410            let snapshot = &*buffer.read(cx);
 9411            let snippet = &snippet;
 9412            snippet
 9413                .tabstops
 9414                .iter()
 9415                .map(|tabstop| {
 9416                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9417                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9418                    });
 9419                    let mut tabstop_ranges = tabstop
 9420                        .ranges
 9421                        .iter()
 9422                        .flat_map(|tabstop_range| {
 9423                            let mut delta = 0_isize;
 9424                            insertion_ranges.iter().map(move |insertion_range| {
 9425                                let insertion_start = insertion_range.start as isize + delta;
 9426                                delta +=
 9427                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9428
 9429                                let start = ((insertion_start + tabstop_range.start) as usize)
 9430                                    .min(snapshot.len());
 9431                                let end = ((insertion_start + tabstop_range.end) as usize)
 9432                                    .min(snapshot.len());
 9433                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9434                            })
 9435                        })
 9436                        .collect::<Vec<_>>();
 9437                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9438
 9439                    Tabstop {
 9440                        is_end_tabstop,
 9441                        ranges: tabstop_ranges,
 9442                        choices: tabstop.choices.clone(),
 9443                    }
 9444                })
 9445                .collect::<Vec<_>>()
 9446        });
 9447        if let Some(tabstop) = tabstops.first() {
 9448            self.change_selections(Default::default(), window, cx, |s| {
 9449                // Reverse order so that the first range is the newest created selection.
 9450                // Completions will use it and autoscroll will prioritize it.
 9451                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9452            });
 9453
 9454            if let Some(choices) = &tabstop.choices {
 9455                if let Some(selection) = tabstop.ranges.first() {
 9456                    self.show_snippet_choices(choices, selection.clone(), cx)
 9457                }
 9458            }
 9459
 9460            // If we're already at the last tabstop and it's at the end of the snippet,
 9461            // we're done, we don't need to keep the state around.
 9462            if !tabstop.is_end_tabstop {
 9463                let choices = tabstops
 9464                    .iter()
 9465                    .map(|tabstop| tabstop.choices.clone())
 9466                    .collect();
 9467
 9468                let ranges = tabstops
 9469                    .into_iter()
 9470                    .map(|tabstop| tabstop.ranges)
 9471                    .collect::<Vec<_>>();
 9472
 9473                self.snippet_stack.push(SnippetState {
 9474                    active_index: 0,
 9475                    ranges,
 9476                    choices,
 9477                });
 9478            }
 9479
 9480            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9481            if self.autoclose_regions.is_empty() {
 9482                let snapshot = self.buffer.read(cx).snapshot(cx);
 9483                for selection in &mut self.selections.all::<Point>(cx) {
 9484                    let selection_head = selection.head();
 9485                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9486                        continue;
 9487                    };
 9488
 9489                    let mut bracket_pair = None;
 9490                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9491                    let prev_chars = snapshot
 9492                        .reversed_chars_at(selection_head)
 9493                        .collect::<String>();
 9494                    for (pair, enabled) in scope.brackets() {
 9495                        if enabled
 9496                            && pair.close
 9497                            && prev_chars.starts_with(pair.start.as_str())
 9498                            && next_chars.starts_with(pair.end.as_str())
 9499                        {
 9500                            bracket_pair = Some(pair.clone());
 9501                            break;
 9502                        }
 9503                    }
 9504                    if let Some(pair) = bracket_pair {
 9505                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9506                        let autoclose_enabled =
 9507                            self.use_autoclose && snapshot_settings.use_autoclose;
 9508                        if autoclose_enabled {
 9509                            let start = snapshot.anchor_after(selection_head);
 9510                            let end = snapshot.anchor_after(selection_head);
 9511                            self.autoclose_regions.push(AutocloseRegion {
 9512                                selection_id: selection.id,
 9513                                range: start..end,
 9514                                pair,
 9515                            });
 9516                        }
 9517                    }
 9518                }
 9519            }
 9520        }
 9521        Ok(())
 9522    }
 9523
 9524    pub fn move_to_next_snippet_tabstop(
 9525        &mut self,
 9526        window: &mut Window,
 9527        cx: &mut Context<Self>,
 9528    ) -> bool {
 9529        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9530    }
 9531
 9532    pub fn move_to_prev_snippet_tabstop(
 9533        &mut self,
 9534        window: &mut Window,
 9535        cx: &mut Context<Self>,
 9536    ) -> bool {
 9537        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9538    }
 9539
 9540    pub fn move_to_snippet_tabstop(
 9541        &mut self,
 9542        bias: Bias,
 9543        window: &mut Window,
 9544        cx: &mut Context<Self>,
 9545    ) -> bool {
 9546        if let Some(mut snippet) = self.snippet_stack.pop() {
 9547            match bias {
 9548                Bias::Left => {
 9549                    if snippet.active_index > 0 {
 9550                        snippet.active_index -= 1;
 9551                    } else {
 9552                        self.snippet_stack.push(snippet);
 9553                        return false;
 9554                    }
 9555                }
 9556                Bias::Right => {
 9557                    if snippet.active_index + 1 < snippet.ranges.len() {
 9558                        snippet.active_index += 1;
 9559                    } else {
 9560                        self.snippet_stack.push(snippet);
 9561                        return false;
 9562                    }
 9563                }
 9564            }
 9565            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9566                self.change_selections(Default::default(), window, cx, |s| {
 9567                    // Reverse order so that the first range is the newest created selection.
 9568                    // Completions will use it and autoscroll will prioritize it.
 9569                    s.select_ranges(current_ranges.iter().rev().cloned())
 9570                });
 9571
 9572                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9573                    if let Some(selection) = current_ranges.first() {
 9574                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9575                    }
 9576                }
 9577
 9578                // If snippet state is not at the last tabstop, push it back on the stack
 9579                if snippet.active_index + 1 < snippet.ranges.len() {
 9580                    self.snippet_stack.push(snippet);
 9581                }
 9582                return true;
 9583            }
 9584        }
 9585
 9586        false
 9587    }
 9588
 9589    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9590        self.transact(window, cx, |this, window, cx| {
 9591            this.select_all(&SelectAll, window, cx);
 9592            this.insert("", window, cx);
 9593        });
 9594    }
 9595
 9596    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9597        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9598        self.transact(window, cx, |this, window, cx| {
 9599            this.select_autoclose_pair(window, cx);
 9600            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9601            if !this.linked_edit_ranges.is_empty() {
 9602                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9603                let snapshot = this.buffer.read(cx).snapshot(cx);
 9604
 9605                for selection in selections.iter() {
 9606                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9607                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9608                    if selection_start.buffer_id != selection_end.buffer_id {
 9609                        continue;
 9610                    }
 9611                    if let Some(ranges) =
 9612                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9613                    {
 9614                        for (buffer, entries) in ranges {
 9615                            linked_ranges.entry(buffer).or_default().extend(entries);
 9616                        }
 9617                    }
 9618                }
 9619            }
 9620
 9621            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9622            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9623            for selection in &mut selections {
 9624                if selection.is_empty() {
 9625                    let old_head = selection.head();
 9626                    let mut new_head =
 9627                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9628                            .to_point(&display_map);
 9629                    if let Some((buffer, line_buffer_range)) = display_map
 9630                        .buffer_snapshot
 9631                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9632                    {
 9633                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9634                        let indent_len = match indent_size.kind {
 9635                            IndentKind::Space => {
 9636                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9637                            }
 9638                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9639                        };
 9640                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9641                            let indent_len = indent_len.get();
 9642                            new_head = cmp::min(
 9643                                new_head,
 9644                                MultiBufferPoint::new(
 9645                                    old_head.row,
 9646                                    ((old_head.column - 1) / indent_len) * indent_len,
 9647                                ),
 9648                            );
 9649                        }
 9650                    }
 9651
 9652                    selection.set_head(new_head, SelectionGoal::None);
 9653                }
 9654            }
 9655
 9656            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9657            this.insert("", window, cx);
 9658            let empty_str: Arc<str> = Arc::from("");
 9659            for (buffer, edits) in linked_ranges {
 9660                let snapshot = buffer.read(cx).snapshot();
 9661                use text::ToPoint as TP;
 9662
 9663                let edits = edits
 9664                    .into_iter()
 9665                    .map(|range| {
 9666                        let end_point = TP::to_point(&range.end, &snapshot);
 9667                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9668
 9669                        if end_point == start_point {
 9670                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9671                                .saturating_sub(1);
 9672                            start_point =
 9673                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9674                        };
 9675
 9676                        (start_point..end_point, empty_str.clone())
 9677                    })
 9678                    .sorted_by_key(|(range, _)| range.start)
 9679                    .collect::<Vec<_>>();
 9680                buffer.update(cx, |this, cx| {
 9681                    this.edit(edits, None, cx);
 9682                })
 9683            }
 9684            this.refresh_inline_completion(true, false, window, cx);
 9685            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9686        });
 9687    }
 9688
 9689    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9690        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9691        self.transact(window, cx, |this, window, cx| {
 9692            this.change_selections(Default::default(), window, cx, |s| {
 9693                s.move_with(|map, selection| {
 9694                    if selection.is_empty() {
 9695                        let cursor = movement::right(map, selection.head());
 9696                        selection.end = cursor;
 9697                        selection.reversed = true;
 9698                        selection.goal = SelectionGoal::None;
 9699                    }
 9700                })
 9701            });
 9702            this.insert("", window, cx);
 9703            this.refresh_inline_completion(true, false, window, cx);
 9704        });
 9705    }
 9706
 9707    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9708        if self.mode.is_single_line() {
 9709            cx.propagate();
 9710            return;
 9711        }
 9712
 9713        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9714        if self.move_to_prev_snippet_tabstop(window, cx) {
 9715            return;
 9716        }
 9717        self.outdent(&Outdent, window, cx);
 9718    }
 9719
 9720    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9721        if self.mode.is_single_line() {
 9722            cx.propagate();
 9723            return;
 9724        }
 9725
 9726        if self.move_to_next_snippet_tabstop(window, cx) {
 9727            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9728            return;
 9729        }
 9730        if self.read_only(cx) {
 9731            return;
 9732        }
 9733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9734        let mut selections = self.selections.all_adjusted(cx);
 9735        let buffer = self.buffer.read(cx);
 9736        let snapshot = buffer.snapshot(cx);
 9737        let rows_iter = selections.iter().map(|s| s.head().row);
 9738        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9739
 9740        let has_some_cursor_in_whitespace = selections
 9741            .iter()
 9742            .filter(|selection| selection.is_empty())
 9743            .any(|selection| {
 9744                let cursor = selection.head();
 9745                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9746                cursor.column < current_indent.len
 9747            });
 9748
 9749        let mut edits = Vec::new();
 9750        let mut prev_edited_row = 0;
 9751        let mut row_delta = 0;
 9752        for selection in &mut selections {
 9753            if selection.start.row != prev_edited_row {
 9754                row_delta = 0;
 9755            }
 9756            prev_edited_row = selection.end.row;
 9757
 9758            // If the selection is non-empty, then increase the indentation of the selected lines.
 9759            if !selection.is_empty() {
 9760                row_delta =
 9761                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9762                continue;
 9763            }
 9764
 9765            let cursor = selection.head();
 9766            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9767            if let Some(suggested_indent) =
 9768                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9769            {
 9770                // Don't do anything if already at suggested indent
 9771                // and there is any other cursor which is not
 9772                if has_some_cursor_in_whitespace
 9773                    && cursor.column == current_indent.len
 9774                    && current_indent.len == suggested_indent.len
 9775                {
 9776                    continue;
 9777                }
 9778
 9779                // Adjust line and move cursor to suggested indent
 9780                // if cursor is not at suggested indent
 9781                if cursor.column < suggested_indent.len
 9782                    && cursor.column <= current_indent.len
 9783                    && current_indent.len <= suggested_indent.len
 9784                {
 9785                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9786                    selection.end = selection.start;
 9787                    if row_delta == 0 {
 9788                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9789                            cursor.row,
 9790                            current_indent,
 9791                            suggested_indent,
 9792                        ));
 9793                        row_delta = suggested_indent.len - current_indent.len;
 9794                    }
 9795                    continue;
 9796                }
 9797
 9798                // If current indent is more than suggested indent
 9799                // only move cursor to current indent and skip indent
 9800                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9801                    selection.start = Point::new(cursor.row, current_indent.len);
 9802                    selection.end = selection.start;
 9803                    continue;
 9804                }
 9805            }
 9806
 9807            // Otherwise, insert a hard or soft tab.
 9808            let settings = buffer.language_settings_at(cursor, cx);
 9809            let tab_size = if settings.hard_tabs {
 9810                IndentSize::tab()
 9811            } else {
 9812                let tab_size = settings.tab_size.get();
 9813                let indent_remainder = snapshot
 9814                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9815                    .flat_map(str::chars)
 9816                    .fold(row_delta % tab_size, |counter: u32, c| {
 9817                        if c == '\t' {
 9818                            0
 9819                        } else {
 9820                            (counter + 1) % tab_size
 9821                        }
 9822                    });
 9823
 9824                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9825                IndentSize::spaces(chars_to_next_tab_stop)
 9826            };
 9827            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9828            selection.end = selection.start;
 9829            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9830            row_delta += tab_size.len;
 9831        }
 9832
 9833        self.transact(window, cx, |this, window, cx| {
 9834            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9835            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9836            this.refresh_inline_completion(true, false, window, cx);
 9837        });
 9838    }
 9839
 9840    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9841        if self.read_only(cx) {
 9842            return;
 9843        }
 9844        if self.mode.is_single_line() {
 9845            cx.propagate();
 9846            return;
 9847        }
 9848
 9849        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9850        let mut selections = self.selections.all::<Point>(cx);
 9851        let mut prev_edited_row = 0;
 9852        let mut row_delta = 0;
 9853        let mut edits = Vec::new();
 9854        let buffer = self.buffer.read(cx);
 9855        let snapshot = buffer.snapshot(cx);
 9856        for selection in &mut selections {
 9857            if selection.start.row != prev_edited_row {
 9858                row_delta = 0;
 9859            }
 9860            prev_edited_row = selection.end.row;
 9861
 9862            row_delta =
 9863                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9864        }
 9865
 9866        self.transact(window, cx, |this, window, cx| {
 9867            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9868            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9869        });
 9870    }
 9871
 9872    fn indent_selection(
 9873        buffer: &MultiBuffer,
 9874        snapshot: &MultiBufferSnapshot,
 9875        selection: &mut Selection<Point>,
 9876        edits: &mut Vec<(Range<Point>, String)>,
 9877        delta_for_start_row: u32,
 9878        cx: &App,
 9879    ) -> u32 {
 9880        let settings = buffer.language_settings_at(selection.start, cx);
 9881        let tab_size = settings.tab_size.get();
 9882        let indent_kind = if settings.hard_tabs {
 9883            IndentKind::Tab
 9884        } else {
 9885            IndentKind::Space
 9886        };
 9887        let mut start_row = selection.start.row;
 9888        let mut end_row = selection.end.row + 1;
 9889
 9890        // If a selection ends at the beginning of a line, don't indent
 9891        // that last line.
 9892        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9893            end_row -= 1;
 9894        }
 9895
 9896        // Avoid re-indenting a row that has already been indented by a
 9897        // previous selection, but still update this selection's column
 9898        // to reflect that indentation.
 9899        if delta_for_start_row > 0 {
 9900            start_row += 1;
 9901            selection.start.column += delta_for_start_row;
 9902            if selection.end.row == selection.start.row {
 9903                selection.end.column += delta_for_start_row;
 9904            }
 9905        }
 9906
 9907        let mut delta_for_end_row = 0;
 9908        let has_multiple_rows = start_row + 1 != end_row;
 9909        for row in start_row..end_row {
 9910            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9911            let indent_delta = match (current_indent.kind, indent_kind) {
 9912                (IndentKind::Space, IndentKind::Space) => {
 9913                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9914                    IndentSize::spaces(columns_to_next_tab_stop)
 9915                }
 9916                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9917                (_, IndentKind::Tab) => IndentSize::tab(),
 9918            };
 9919
 9920            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9921                0
 9922            } else {
 9923                selection.start.column
 9924            };
 9925            let row_start = Point::new(row, start);
 9926            edits.push((
 9927                row_start..row_start,
 9928                indent_delta.chars().collect::<String>(),
 9929            ));
 9930
 9931            // Update this selection's endpoints to reflect the indentation.
 9932            if row == selection.start.row {
 9933                selection.start.column += indent_delta.len;
 9934            }
 9935            if row == selection.end.row {
 9936                selection.end.column += indent_delta.len;
 9937                delta_for_end_row = indent_delta.len;
 9938            }
 9939        }
 9940
 9941        if selection.start.row == selection.end.row {
 9942            delta_for_start_row + delta_for_end_row
 9943        } else {
 9944            delta_for_end_row
 9945        }
 9946    }
 9947
 9948    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9949        if self.read_only(cx) {
 9950            return;
 9951        }
 9952        if self.mode.is_single_line() {
 9953            cx.propagate();
 9954            return;
 9955        }
 9956
 9957        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9958        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9959        let selections = self.selections.all::<Point>(cx);
 9960        let mut deletion_ranges = Vec::new();
 9961        let mut last_outdent = None;
 9962        {
 9963            let buffer = self.buffer.read(cx);
 9964            let snapshot = buffer.snapshot(cx);
 9965            for selection in &selections {
 9966                let settings = buffer.language_settings_at(selection.start, cx);
 9967                let tab_size = settings.tab_size.get();
 9968                let mut rows = selection.spanned_rows(false, &display_map);
 9969
 9970                // Avoid re-outdenting a row that has already been outdented by a
 9971                // previous selection.
 9972                if let Some(last_row) = last_outdent {
 9973                    if last_row == rows.start {
 9974                        rows.start = rows.start.next_row();
 9975                    }
 9976                }
 9977                let has_multiple_rows = rows.len() > 1;
 9978                for row in rows.iter_rows() {
 9979                    let indent_size = snapshot.indent_size_for_line(row);
 9980                    if indent_size.len > 0 {
 9981                        let deletion_len = match indent_size.kind {
 9982                            IndentKind::Space => {
 9983                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9984                                if columns_to_prev_tab_stop == 0 {
 9985                                    tab_size
 9986                                } else {
 9987                                    columns_to_prev_tab_stop
 9988                                }
 9989                            }
 9990                            IndentKind::Tab => 1,
 9991                        };
 9992                        let start = if has_multiple_rows
 9993                            || deletion_len > selection.start.column
 9994                            || indent_size.len < selection.start.column
 9995                        {
 9996                            0
 9997                        } else {
 9998                            selection.start.column - deletion_len
 9999                        };
10000                        deletion_ranges.push(
10001                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10002                        );
10003                        last_outdent = Some(row);
10004                    }
10005                }
10006            }
10007        }
10008
10009        self.transact(window, cx, |this, window, cx| {
10010            this.buffer.update(cx, |buffer, cx| {
10011                let empty_str: Arc<str> = Arc::default();
10012                buffer.edit(
10013                    deletion_ranges
10014                        .into_iter()
10015                        .map(|range| (range, empty_str.clone())),
10016                    None,
10017                    cx,
10018                );
10019            });
10020            let selections = this.selections.all::<usize>(cx);
10021            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10022        });
10023    }
10024
10025    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10026        if self.read_only(cx) {
10027            return;
10028        }
10029        if self.mode.is_single_line() {
10030            cx.propagate();
10031            return;
10032        }
10033
10034        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10035        let selections = self
10036            .selections
10037            .all::<usize>(cx)
10038            .into_iter()
10039            .map(|s| s.range());
10040
10041        self.transact(window, cx, |this, window, cx| {
10042            this.buffer.update(cx, |buffer, cx| {
10043                buffer.autoindent_ranges(selections, cx);
10044            });
10045            let selections = this.selections.all::<usize>(cx);
10046            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10047        });
10048    }
10049
10050    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10051        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10052        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10053        let selections = self.selections.all::<Point>(cx);
10054
10055        let mut new_cursors = Vec::new();
10056        let mut edit_ranges = Vec::new();
10057        let mut selections = selections.iter().peekable();
10058        while let Some(selection) = selections.next() {
10059            let mut rows = selection.spanned_rows(false, &display_map);
10060            let goal_display_column = selection.head().to_display_point(&display_map).column();
10061
10062            // Accumulate contiguous regions of rows that we want to delete.
10063            while let Some(next_selection) = selections.peek() {
10064                let next_rows = next_selection.spanned_rows(false, &display_map);
10065                if next_rows.start <= rows.end {
10066                    rows.end = next_rows.end;
10067                    selections.next().unwrap();
10068                } else {
10069                    break;
10070                }
10071            }
10072
10073            let buffer = &display_map.buffer_snapshot;
10074            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10075            let edit_end;
10076            let cursor_buffer_row;
10077            if buffer.max_point().row >= rows.end.0 {
10078                // If there's a line after the range, delete the \n from the end of the row range
10079                // and position the cursor on the next line.
10080                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10081                cursor_buffer_row = rows.end;
10082            } else {
10083                // If there isn't a line after the range, delete the \n from the line before the
10084                // start of the row range and position the cursor there.
10085                edit_start = edit_start.saturating_sub(1);
10086                edit_end = buffer.len();
10087                cursor_buffer_row = rows.start.previous_row();
10088            }
10089
10090            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10091            *cursor.column_mut() =
10092                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10093
10094            new_cursors.push((
10095                selection.id,
10096                buffer.anchor_after(cursor.to_point(&display_map)),
10097            ));
10098            edit_ranges.push(edit_start..edit_end);
10099        }
10100
10101        self.transact(window, cx, |this, window, cx| {
10102            let buffer = this.buffer.update(cx, |buffer, cx| {
10103                let empty_str: Arc<str> = Arc::default();
10104                buffer.edit(
10105                    edit_ranges
10106                        .into_iter()
10107                        .map(|range| (range, empty_str.clone())),
10108                    None,
10109                    cx,
10110                );
10111                buffer.snapshot(cx)
10112            });
10113            let new_selections = new_cursors
10114                .into_iter()
10115                .map(|(id, cursor)| {
10116                    let cursor = cursor.to_point(&buffer);
10117                    Selection {
10118                        id,
10119                        start: cursor,
10120                        end: cursor,
10121                        reversed: false,
10122                        goal: SelectionGoal::None,
10123                    }
10124                })
10125                .collect();
10126
10127            this.change_selections(Default::default(), window, cx, |s| {
10128                s.select(new_selections);
10129            });
10130        });
10131    }
10132
10133    pub fn join_lines_impl(
10134        &mut self,
10135        insert_whitespace: bool,
10136        window: &mut Window,
10137        cx: &mut Context<Self>,
10138    ) {
10139        if self.read_only(cx) {
10140            return;
10141        }
10142        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10143        for selection in self.selections.all::<Point>(cx) {
10144            let start = MultiBufferRow(selection.start.row);
10145            // Treat single line selections as if they include the next line. Otherwise this action
10146            // would do nothing for single line selections individual cursors.
10147            let end = if selection.start.row == selection.end.row {
10148                MultiBufferRow(selection.start.row + 1)
10149            } else {
10150                MultiBufferRow(selection.end.row)
10151            };
10152
10153            if let Some(last_row_range) = row_ranges.last_mut() {
10154                if start <= last_row_range.end {
10155                    last_row_range.end = end;
10156                    continue;
10157                }
10158            }
10159            row_ranges.push(start..end);
10160        }
10161
10162        let snapshot = self.buffer.read(cx).snapshot(cx);
10163        let mut cursor_positions = Vec::new();
10164        for row_range in &row_ranges {
10165            let anchor = snapshot.anchor_before(Point::new(
10166                row_range.end.previous_row().0,
10167                snapshot.line_len(row_range.end.previous_row()),
10168            ));
10169            cursor_positions.push(anchor..anchor);
10170        }
10171
10172        self.transact(window, cx, |this, window, cx| {
10173            for row_range in row_ranges.into_iter().rev() {
10174                for row in row_range.iter_rows().rev() {
10175                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10176                    let next_line_row = row.next_row();
10177                    let indent = snapshot.indent_size_for_line(next_line_row);
10178                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10179
10180                    let replace =
10181                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10182                            " "
10183                        } else {
10184                            ""
10185                        };
10186
10187                    this.buffer.update(cx, |buffer, cx| {
10188                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10189                    });
10190                }
10191            }
10192
10193            this.change_selections(Default::default(), window, cx, |s| {
10194                s.select_anchor_ranges(cursor_positions)
10195            });
10196        });
10197    }
10198
10199    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10200        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10201        self.join_lines_impl(true, window, cx);
10202    }
10203
10204    pub fn sort_lines_case_sensitive(
10205        &mut self,
10206        _: &SortLinesCaseSensitive,
10207        window: &mut Window,
10208        cx: &mut Context<Self>,
10209    ) {
10210        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10211    }
10212
10213    pub fn sort_lines_by_length(
10214        &mut self,
10215        _: &SortLinesByLength,
10216        window: &mut Window,
10217        cx: &mut Context<Self>,
10218    ) {
10219        self.manipulate_immutable_lines(window, cx, |lines| {
10220            lines.sort_by_key(|&line| line.chars().count())
10221        })
10222    }
10223
10224    pub fn sort_lines_case_insensitive(
10225        &mut self,
10226        _: &SortLinesCaseInsensitive,
10227        window: &mut Window,
10228        cx: &mut Context<Self>,
10229    ) {
10230        self.manipulate_immutable_lines(window, cx, |lines| {
10231            lines.sort_by_key(|line| line.to_lowercase())
10232        })
10233    }
10234
10235    pub fn unique_lines_case_insensitive(
10236        &mut self,
10237        _: &UniqueLinesCaseInsensitive,
10238        window: &mut Window,
10239        cx: &mut Context<Self>,
10240    ) {
10241        self.manipulate_immutable_lines(window, cx, |lines| {
10242            let mut seen = HashSet::default();
10243            lines.retain(|line| seen.insert(line.to_lowercase()));
10244        })
10245    }
10246
10247    pub fn unique_lines_case_sensitive(
10248        &mut self,
10249        _: &UniqueLinesCaseSensitive,
10250        window: &mut Window,
10251        cx: &mut Context<Self>,
10252    ) {
10253        self.manipulate_immutable_lines(window, cx, |lines| {
10254            let mut seen = HashSet::default();
10255            lines.retain(|line| seen.insert(*line));
10256        })
10257    }
10258
10259    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10260        let Some(project) = self.project.clone() else {
10261            return;
10262        };
10263        self.reload(project, window, cx)
10264            .detach_and_notify_err(window, cx);
10265    }
10266
10267    pub fn restore_file(
10268        &mut self,
10269        _: &::git::RestoreFile,
10270        window: &mut Window,
10271        cx: &mut Context<Self>,
10272    ) {
10273        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10274        let mut buffer_ids = HashSet::default();
10275        let snapshot = self.buffer().read(cx).snapshot(cx);
10276        for selection in self.selections.all::<usize>(cx) {
10277            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10278        }
10279
10280        let buffer = self.buffer().read(cx);
10281        let ranges = buffer_ids
10282            .into_iter()
10283            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10284            .collect::<Vec<_>>();
10285
10286        self.restore_hunks_in_ranges(ranges, window, cx);
10287    }
10288
10289    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10290        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10291        let selections = self
10292            .selections
10293            .all(cx)
10294            .into_iter()
10295            .map(|s| s.range())
10296            .collect();
10297        self.restore_hunks_in_ranges(selections, window, cx);
10298    }
10299
10300    pub fn restore_hunks_in_ranges(
10301        &mut self,
10302        ranges: Vec<Range<Point>>,
10303        window: &mut Window,
10304        cx: &mut Context<Editor>,
10305    ) {
10306        let mut revert_changes = HashMap::default();
10307        let chunk_by = self
10308            .snapshot(window, cx)
10309            .hunks_for_ranges(ranges)
10310            .into_iter()
10311            .chunk_by(|hunk| hunk.buffer_id);
10312        for (buffer_id, hunks) in &chunk_by {
10313            let hunks = hunks.collect::<Vec<_>>();
10314            for hunk in &hunks {
10315                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10316            }
10317            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10318        }
10319        drop(chunk_by);
10320        if !revert_changes.is_empty() {
10321            self.transact(window, cx, |editor, window, cx| {
10322                editor.restore(revert_changes, window, cx);
10323            });
10324        }
10325    }
10326
10327    pub fn open_active_item_in_terminal(
10328        &mut self,
10329        _: &OpenInTerminal,
10330        window: &mut Window,
10331        cx: &mut Context<Self>,
10332    ) {
10333        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10334            let project_path = buffer.read(cx).project_path(cx)?;
10335            let project = self.project.as_ref()?.read(cx);
10336            let entry = project.entry_for_path(&project_path, cx)?;
10337            let parent = match &entry.canonical_path {
10338                Some(canonical_path) => canonical_path.to_path_buf(),
10339                None => project.absolute_path(&project_path, cx)?,
10340            }
10341            .parent()?
10342            .to_path_buf();
10343            Some(parent)
10344        }) {
10345            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10346        }
10347    }
10348
10349    fn set_breakpoint_context_menu(
10350        &mut self,
10351        display_row: DisplayRow,
10352        position: Option<Anchor>,
10353        clicked_point: gpui::Point<Pixels>,
10354        window: &mut Window,
10355        cx: &mut Context<Self>,
10356    ) {
10357        let source = self
10358            .buffer
10359            .read(cx)
10360            .snapshot(cx)
10361            .anchor_before(Point::new(display_row.0, 0u32));
10362
10363        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10364
10365        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10366            self,
10367            source,
10368            clicked_point,
10369            context_menu,
10370            window,
10371            cx,
10372        );
10373    }
10374
10375    fn add_edit_breakpoint_block(
10376        &mut self,
10377        anchor: Anchor,
10378        breakpoint: &Breakpoint,
10379        edit_action: BreakpointPromptEditAction,
10380        window: &mut Window,
10381        cx: &mut Context<Self>,
10382    ) {
10383        let weak_editor = cx.weak_entity();
10384        let bp_prompt = cx.new(|cx| {
10385            BreakpointPromptEditor::new(
10386                weak_editor,
10387                anchor,
10388                breakpoint.clone(),
10389                edit_action,
10390                window,
10391                cx,
10392            )
10393        });
10394
10395        let height = bp_prompt.update(cx, |this, cx| {
10396            this.prompt
10397                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10398        });
10399        let cloned_prompt = bp_prompt.clone();
10400        let blocks = vec![BlockProperties {
10401            style: BlockStyle::Sticky,
10402            placement: BlockPlacement::Above(anchor),
10403            height: Some(height),
10404            render: Arc::new(move |cx| {
10405                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10406                cloned_prompt.clone().into_any_element()
10407            }),
10408            priority: 0,
10409            render_in_minimap: true,
10410        }];
10411
10412        let focus_handle = bp_prompt.focus_handle(cx);
10413        window.focus(&focus_handle);
10414
10415        let block_ids = self.insert_blocks(blocks, None, cx);
10416        bp_prompt.update(cx, |prompt, _| {
10417            prompt.add_block_ids(block_ids);
10418        });
10419    }
10420
10421    pub(crate) fn breakpoint_at_row(
10422        &self,
10423        row: u32,
10424        window: &mut Window,
10425        cx: &mut Context<Self>,
10426    ) -> Option<(Anchor, Breakpoint)> {
10427        let snapshot = self.snapshot(window, cx);
10428        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10429
10430        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10431    }
10432
10433    pub(crate) fn breakpoint_at_anchor(
10434        &self,
10435        breakpoint_position: Anchor,
10436        snapshot: &EditorSnapshot,
10437        cx: &mut Context<Self>,
10438    ) -> Option<(Anchor, Breakpoint)> {
10439        let project = self.project.clone()?;
10440
10441        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10442            snapshot
10443                .buffer_snapshot
10444                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10445        })?;
10446
10447        let enclosing_excerpt = breakpoint_position.excerpt_id;
10448        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10449        let buffer_snapshot = buffer.read(cx).snapshot();
10450
10451        let row = buffer_snapshot
10452            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10453            .row;
10454
10455        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10456        let anchor_end = snapshot
10457            .buffer_snapshot
10458            .anchor_after(Point::new(row, line_len));
10459
10460        let bp = self
10461            .breakpoint_store
10462            .as_ref()?
10463            .read_with(cx, |breakpoint_store, cx| {
10464                breakpoint_store
10465                    .breakpoints(
10466                        &buffer,
10467                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10468                        &buffer_snapshot,
10469                        cx,
10470                    )
10471                    .next()
10472                    .and_then(|(bp, _)| {
10473                        let breakpoint_row = buffer_snapshot
10474                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10475                            .row;
10476
10477                        if breakpoint_row == row {
10478                            snapshot
10479                                .buffer_snapshot
10480                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10481                                .map(|position| (position, bp.bp.clone()))
10482                        } else {
10483                            None
10484                        }
10485                    })
10486            });
10487        bp
10488    }
10489
10490    pub fn edit_log_breakpoint(
10491        &mut self,
10492        _: &EditLogBreakpoint,
10493        window: &mut Window,
10494        cx: &mut Context<Self>,
10495    ) {
10496        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10497            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10498                message: None,
10499                state: BreakpointState::Enabled,
10500                condition: None,
10501                hit_condition: None,
10502            });
10503
10504            self.add_edit_breakpoint_block(
10505                anchor,
10506                &breakpoint,
10507                BreakpointPromptEditAction::Log,
10508                window,
10509                cx,
10510            );
10511        }
10512    }
10513
10514    fn breakpoints_at_cursors(
10515        &self,
10516        window: &mut Window,
10517        cx: &mut Context<Self>,
10518    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10519        let snapshot = self.snapshot(window, cx);
10520        let cursors = self
10521            .selections
10522            .disjoint_anchors()
10523            .into_iter()
10524            .map(|selection| {
10525                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10526
10527                let breakpoint_position = self
10528                    .breakpoint_at_row(cursor_position.row, window, cx)
10529                    .map(|bp| bp.0)
10530                    .unwrap_or_else(|| {
10531                        snapshot
10532                            .display_snapshot
10533                            .buffer_snapshot
10534                            .anchor_after(Point::new(cursor_position.row, 0))
10535                    });
10536
10537                let breakpoint = self
10538                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10539                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10540
10541                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10542            })
10543            // There might be multiple cursors on the same line; all of them should have the same anchors though as their breakpoints positions, which makes it possible to sort and dedup the list.
10544            .collect::<HashMap<Anchor, _>>();
10545
10546        cursors.into_iter().collect()
10547    }
10548
10549    pub fn enable_breakpoint(
10550        &mut self,
10551        _: &crate::actions::EnableBreakpoint,
10552        window: &mut Window,
10553        cx: &mut Context<Self>,
10554    ) {
10555        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10556            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10557                continue;
10558            };
10559            self.edit_breakpoint_at_anchor(
10560                anchor,
10561                breakpoint,
10562                BreakpointEditAction::InvertState,
10563                cx,
10564            );
10565        }
10566    }
10567
10568    pub fn disable_breakpoint(
10569        &mut self,
10570        _: &crate::actions::DisableBreakpoint,
10571        window: &mut Window,
10572        cx: &mut Context<Self>,
10573    ) {
10574        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10575            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10576                continue;
10577            };
10578            self.edit_breakpoint_at_anchor(
10579                anchor,
10580                breakpoint,
10581                BreakpointEditAction::InvertState,
10582                cx,
10583            );
10584        }
10585    }
10586
10587    pub fn toggle_breakpoint(
10588        &mut self,
10589        _: &crate::actions::ToggleBreakpoint,
10590        window: &mut Window,
10591        cx: &mut Context<Self>,
10592    ) {
10593        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10594            if let Some(breakpoint) = breakpoint {
10595                self.edit_breakpoint_at_anchor(
10596                    anchor,
10597                    breakpoint,
10598                    BreakpointEditAction::Toggle,
10599                    cx,
10600                );
10601            } else {
10602                self.edit_breakpoint_at_anchor(
10603                    anchor,
10604                    Breakpoint::new_standard(),
10605                    BreakpointEditAction::Toggle,
10606                    cx,
10607                );
10608            }
10609        }
10610    }
10611
10612    pub fn edit_breakpoint_at_anchor(
10613        &mut self,
10614        breakpoint_position: Anchor,
10615        breakpoint: Breakpoint,
10616        edit_action: BreakpointEditAction,
10617        cx: &mut Context<Self>,
10618    ) {
10619        let Some(breakpoint_store) = &self.breakpoint_store else {
10620            return;
10621        };
10622
10623        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10624            if breakpoint_position == Anchor::min() {
10625                self.buffer()
10626                    .read(cx)
10627                    .excerpt_buffer_ids()
10628                    .into_iter()
10629                    .next()
10630            } else {
10631                None
10632            }
10633        }) else {
10634            return;
10635        };
10636
10637        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10638            return;
10639        };
10640
10641        breakpoint_store.update(cx, |breakpoint_store, cx| {
10642            breakpoint_store.toggle_breakpoint(
10643                buffer,
10644                BreakpointWithPosition {
10645                    position: breakpoint_position.text_anchor,
10646                    bp: breakpoint,
10647                },
10648                edit_action,
10649                cx,
10650            );
10651        });
10652
10653        cx.notify();
10654    }
10655
10656    #[cfg(any(test, feature = "test-support"))]
10657    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10658        self.breakpoint_store.clone()
10659    }
10660
10661    pub fn prepare_restore_change(
10662        &self,
10663        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10664        hunk: &MultiBufferDiffHunk,
10665        cx: &mut App,
10666    ) -> Option<()> {
10667        if hunk.is_created_file() {
10668            return None;
10669        }
10670        let buffer = self.buffer.read(cx);
10671        let diff = buffer.diff_for(hunk.buffer_id)?;
10672        let buffer = buffer.buffer(hunk.buffer_id)?;
10673        let buffer = buffer.read(cx);
10674        let original_text = diff
10675            .read(cx)
10676            .base_text()
10677            .as_rope()
10678            .slice(hunk.diff_base_byte_range.clone());
10679        let buffer_snapshot = buffer.snapshot();
10680        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10681        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10682            probe
10683                .0
10684                .start
10685                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10686                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10687        }) {
10688            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10689            Some(())
10690        } else {
10691            None
10692        }
10693    }
10694
10695    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10696        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10697    }
10698
10699    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10700        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10701    }
10702
10703    fn manipulate_lines<M>(
10704        &mut self,
10705        window: &mut Window,
10706        cx: &mut Context<Self>,
10707        mut manipulate: M,
10708    ) where
10709        M: FnMut(&str) -> LineManipulationResult,
10710    {
10711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10712
10713        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10714        let buffer = self.buffer.read(cx).snapshot(cx);
10715
10716        let mut edits = Vec::new();
10717
10718        let selections = self.selections.all::<Point>(cx);
10719        let mut selections = selections.iter().peekable();
10720        let mut contiguous_row_selections = Vec::new();
10721        let mut new_selections = Vec::new();
10722        let mut added_lines = 0;
10723        let mut removed_lines = 0;
10724
10725        while let Some(selection) = selections.next() {
10726            let (start_row, end_row) = consume_contiguous_rows(
10727                &mut contiguous_row_selections,
10728                selection,
10729                &display_map,
10730                &mut selections,
10731            );
10732
10733            let start_point = Point::new(start_row.0, 0);
10734            let end_point = Point::new(
10735                end_row.previous_row().0,
10736                buffer.line_len(end_row.previous_row()),
10737            );
10738            let text = buffer
10739                .text_for_range(start_point..end_point)
10740                .collect::<String>();
10741
10742            let LineManipulationResult {
10743                new_text,
10744                line_count_before,
10745                line_count_after,
10746            } = manipulate(&text);
10747
10748            edits.push((start_point..end_point, new_text));
10749
10750            // Selections must change based on added and removed line count
10751            let start_row =
10752                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10753            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10754            new_selections.push(Selection {
10755                id: selection.id,
10756                start: start_row,
10757                end: end_row,
10758                goal: SelectionGoal::None,
10759                reversed: selection.reversed,
10760            });
10761
10762            if line_count_after > line_count_before {
10763                added_lines += line_count_after - line_count_before;
10764            } else if line_count_before > line_count_after {
10765                removed_lines += line_count_before - line_count_after;
10766            }
10767        }
10768
10769        self.transact(window, cx, |this, window, cx| {
10770            let buffer = this.buffer.update(cx, |buffer, cx| {
10771                buffer.edit(edits, None, cx);
10772                buffer.snapshot(cx)
10773            });
10774
10775            // Recalculate offsets on newly edited buffer
10776            let new_selections = new_selections
10777                .iter()
10778                .map(|s| {
10779                    let start_point = Point::new(s.start.0, 0);
10780                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10781                    Selection {
10782                        id: s.id,
10783                        start: buffer.point_to_offset(start_point),
10784                        end: buffer.point_to_offset(end_point),
10785                        goal: s.goal,
10786                        reversed: s.reversed,
10787                    }
10788                })
10789                .collect();
10790
10791            this.change_selections(Default::default(), window, cx, |s| {
10792                s.select(new_selections);
10793            });
10794
10795            this.request_autoscroll(Autoscroll::fit(), cx);
10796        });
10797    }
10798
10799    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10800        self.manipulate_text(window, cx, |text| {
10801            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10802            if has_upper_case_characters {
10803                text.to_lowercase()
10804            } else {
10805                text.to_uppercase()
10806            }
10807        })
10808    }
10809
10810    fn manipulate_immutable_lines<Fn>(
10811        &mut self,
10812        window: &mut Window,
10813        cx: &mut Context<Self>,
10814        mut callback: Fn,
10815    ) where
10816        Fn: FnMut(&mut Vec<&str>),
10817    {
10818        self.manipulate_lines(window, cx, |text| {
10819            let mut lines: Vec<&str> = text.split('\n').collect();
10820            let line_count_before = lines.len();
10821
10822            callback(&mut lines);
10823
10824            LineManipulationResult {
10825                new_text: lines.join("\n"),
10826                line_count_before,
10827                line_count_after: lines.len(),
10828            }
10829        });
10830    }
10831
10832    fn manipulate_mutable_lines<Fn>(
10833        &mut self,
10834        window: &mut Window,
10835        cx: &mut Context<Self>,
10836        mut callback: Fn,
10837    ) where
10838        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10839    {
10840        self.manipulate_lines(window, cx, |text| {
10841            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10842            let line_count_before = lines.len();
10843
10844            callback(&mut lines);
10845
10846            LineManipulationResult {
10847                new_text: lines.join("\n"),
10848                line_count_before,
10849                line_count_after: lines.len(),
10850            }
10851        });
10852    }
10853
10854    pub fn convert_indentation_to_spaces(
10855        &mut self,
10856        _: &ConvertIndentationToSpaces,
10857        window: &mut Window,
10858        cx: &mut Context<Self>,
10859    ) {
10860        let settings = self.buffer.read(cx).language_settings(cx);
10861        let tab_size = settings.tab_size.get() as usize;
10862
10863        self.manipulate_mutable_lines(window, cx, |lines| {
10864            // Allocates a reasonably sized scratch buffer once for the whole loop
10865            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10866            // Avoids recomputing spaces that could be inserted many times
10867            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10868                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10869                .collect();
10870
10871            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10872                let mut chars = line.as_ref().chars();
10873                let mut col = 0;
10874                let mut changed = false;
10875
10876                while let Some(ch) = chars.next() {
10877                    match ch {
10878                        ' ' => {
10879                            reindented_line.push(' ');
10880                            col += 1;
10881                        }
10882                        '\t' => {
10883                            // \t are converted to spaces depending on the current column
10884                            let spaces_len = tab_size - (col % tab_size);
10885                            reindented_line.extend(&space_cache[spaces_len - 1]);
10886                            col += spaces_len;
10887                            changed = true;
10888                        }
10889                        _ => {
10890                            // If we dont append before break, the character is consumed
10891                            reindented_line.push(ch);
10892                            break;
10893                        }
10894                    }
10895                }
10896
10897                if !changed {
10898                    reindented_line.clear();
10899                    continue;
10900                }
10901                // Append the rest of the line and replace old reference with new one
10902                reindented_line.extend(chars);
10903                *line = Cow::Owned(reindented_line.clone());
10904                reindented_line.clear();
10905            }
10906        });
10907    }
10908
10909    pub fn convert_indentation_to_tabs(
10910        &mut self,
10911        _: &ConvertIndentationToTabs,
10912        window: &mut Window,
10913        cx: &mut Context<Self>,
10914    ) {
10915        let settings = self.buffer.read(cx).language_settings(cx);
10916        let tab_size = settings.tab_size.get() as usize;
10917
10918        self.manipulate_mutable_lines(window, cx, |lines| {
10919            // Allocates a reasonably sized buffer once for the whole loop
10920            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10921            // Avoids recomputing spaces that could be inserted many times
10922            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10923                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10924                .collect();
10925
10926            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10927                let mut chars = line.chars();
10928                let mut spaces_count = 0;
10929                let mut first_non_indent_char = None;
10930                let mut changed = false;
10931
10932                while let Some(ch) = chars.next() {
10933                    match ch {
10934                        ' ' => {
10935                            // Keep track of spaces. Append \t when we reach tab_size
10936                            spaces_count += 1;
10937                            changed = true;
10938                            if spaces_count == tab_size {
10939                                reindented_line.push('\t');
10940                                spaces_count = 0;
10941                            }
10942                        }
10943                        '\t' => {
10944                            reindented_line.push('\t');
10945                            spaces_count = 0;
10946                        }
10947                        _ => {
10948                            // Dont append it yet, we might have remaining spaces
10949                            first_non_indent_char = Some(ch);
10950                            break;
10951                        }
10952                    }
10953                }
10954
10955                if !changed {
10956                    reindented_line.clear();
10957                    continue;
10958                }
10959                // Remaining spaces that didn't make a full tab stop
10960                if spaces_count > 0 {
10961                    reindented_line.extend(&space_cache[spaces_count - 1]);
10962                }
10963                // If we consume an extra character that was not indentation, add it back
10964                if let Some(extra_char) = first_non_indent_char {
10965                    reindented_line.push(extra_char);
10966                }
10967                // Append the rest of the line and replace old reference with new one
10968                reindented_line.extend(chars);
10969                *line = Cow::Owned(reindented_line.clone());
10970                reindented_line.clear();
10971            }
10972        });
10973    }
10974
10975    pub fn convert_to_upper_case(
10976        &mut self,
10977        _: &ConvertToUpperCase,
10978        window: &mut Window,
10979        cx: &mut Context<Self>,
10980    ) {
10981        self.manipulate_text(window, cx, |text| text.to_uppercase())
10982    }
10983
10984    pub fn convert_to_lower_case(
10985        &mut self,
10986        _: &ConvertToLowerCase,
10987        window: &mut Window,
10988        cx: &mut Context<Self>,
10989    ) {
10990        self.manipulate_text(window, cx, |text| text.to_lowercase())
10991    }
10992
10993    pub fn convert_to_title_case(
10994        &mut self,
10995        _: &ConvertToTitleCase,
10996        window: &mut Window,
10997        cx: &mut Context<Self>,
10998    ) {
10999        self.manipulate_text(window, cx, |text| {
11000            text.split('\n')
11001                .map(|line| line.to_case(Case::Title))
11002                .join("\n")
11003        })
11004    }
11005
11006    pub fn convert_to_snake_case(
11007        &mut self,
11008        _: &ConvertToSnakeCase,
11009        window: &mut Window,
11010        cx: &mut Context<Self>,
11011    ) {
11012        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11013    }
11014
11015    pub fn convert_to_kebab_case(
11016        &mut self,
11017        _: &ConvertToKebabCase,
11018        window: &mut Window,
11019        cx: &mut Context<Self>,
11020    ) {
11021        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11022    }
11023
11024    pub fn convert_to_upper_camel_case(
11025        &mut self,
11026        _: &ConvertToUpperCamelCase,
11027        window: &mut Window,
11028        cx: &mut Context<Self>,
11029    ) {
11030        self.manipulate_text(window, cx, |text| {
11031            text.split('\n')
11032                .map(|line| line.to_case(Case::UpperCamel))
11033                .join("\n")
11034        })
11035    }
11036
11037    pub fn convert_to_lower_camel_case(
11038        &mut self,
11039        _: &ConvertToLowerCamelCase,
11040        window: &mut Window,
11041        cx: &mut Context<Self>,
11042    ) {
11043        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11044    }
11045
11046    pub fn convert_to_opposite_case(
11047        &mut self,
11048        _: &ConvertToOppositeCase,
11049        window: &mut Window,
11050        cx: &mut Context<Self>,
11051    ) {
11052        self.manipulate_text(window, cx, |text| {
11053            text.chars()
11054                .fold(String::with_capacity(text.len()), |mut t, c| {
11055                    if c.is_uppercase() {
11056                        t.extend(c.to_lowercase());
11057                    } else {
11058                        t.extend(c.to_uppercase());
11059                    }
11060                    t
11061                })
11062        })
11063    }
11064
11065    pub fn convert_to_rot13(
11066        &mut self,
11067        _: &ConvertToRot13,
11068        window: &mut Window,
11069        cx: &mut Context<Self>,
11070    ) {
11071        self.manipulate_text(window, cx, |text| {
11072            text.chars()
11073                .map(|c| match c {
11074                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11075                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11076                    _ => c,
11077                })
11078                .collect()
11079        })
11080    }
11081
11082    pub fn convert_to_rot47(
11083        &mut self,
11084        _: &ConvertToRot47,
11085        window: &mut Window,
11086        cx: &mut Context<Self>,
11087    ) {
11088        self.manipulate_text(window, cx, |text| {
11089            text.chars()
11090                .map(|c| {
11091                    let code_point = c as u32;
11092                    if code_point >= 33 && code_point <= 126 {
11093                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11094                    }
11095                    c
11096                })
11097                .collect()
11098        })
11099    }
11100
11101    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11102    where
11103        Fn: FnMut(&str) -> String,
11104    {
11105        let buffer = self.buffer.read(cx).snapshot(cx);
11106
11107        let mut new_selections = Vec::new();
11108        let mut edits = Vec::new();
11109        let mut selection_adjustment = 0i32;
11110
11111        for selection in self.selections.all::<usize>(cx) {
11112            let selection_is_empty = selection.is_empty();
11113
11114            let (start, end) = if selection_is_empty {
11115                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11116                (word_range.start, word_range.end)
11117            } else {
11118                (selection.start, selection.end)
11119            };
11120
11121            let text = buffer.text_for_range(start..end).collect::<String>();
11122            let old_length = text.len() as i32;
11123            let text = callback(&text);
11124
11125            new_selections.push(Selection {
11126                start: (start as i32 - selection_adjustment) as usize,
11127                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11128                goal: SelectionGoal::None,
11129                ..selection
11130            });
11131
11132            selection_adjustment += old_length - text.len() as i32;
11133
11134            edits.push((start..end, text));
11135        }
11136
11137        self.transact(window, cx, |this, window, cx| {
11138            this.buffer.update(cx, |buffer, cx| {
11139                buffer.edit(edits, None, cx);
11140            });
11141
11142            this.change_selections(Default::default(), window, cx, |s| {
11143                s.select(new_selections);
11144            });
11145
11146            this.request_autoscroll(Autoscroll::fit(), cx);
11147        });
11148    }
11149
11150    pub fn move_selection_on_drop(
11151        &mut self,
11152        selection: &Selection<Anchor>,
11153        target: DisplayPoint,
11154        is_cut: bool,
11155        window: &mut Window,
11156        cx: &mut Context<Self>,
11157    ) {
11158        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11159        let buffer = &display_map.buffer_snapshot;
11160        let mut edits = Vec::new();
11161        let insert_point = display_map
11162            .clip_point(target, Bias::Left)
11163            .to_point(&display_map);
11164        let text = buffer
11165            .text_for_range(selection.start..selection.end)
11166            .collect::<String>();
11167        if is_cut {
11168            edits.push(((selection.start..selection.end), String::new()));
11169        }
11170        let insert_anchor = buffer.anchor_before(insert_point);
11171        edits.push(((insert_anchor..insert_anchor), text));
11172        let last_edit_start = insert_anchor.bias_left(buffer);
11173        let last_edit_end = insert_anchor.bias_right(buffer);
11174        self.transact(window, cx, |this, window, cx| {
11175            this.buffer.update(cx, |buffer, cx| {
11176                buffer.edit(edits, None, cx);
11177            });
11178            this.change_selections(Default::default(), window, cx, |s| {
11179                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11180            });
11181        });
11182    }
11183
11184    pub fn clear_selection_drag_state(&mut self) {
11185        self.selection_drag_state = SelectionDragState::None;
11186    }
11187
11188    pub fn duplicate(
11189        &mut self,
11190        upwards: bool,
11191        whole_lines: bool,
11192        window: &mut Window,
11193        cx: &mut Context<Self>,
11194    ) {
11195        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11196
11197        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11198        let buffer = &display_map.buffer_snapshot;
11199        let selections = self.selections.all::<Point>(cx);
11200
11201        let mut edits = Vec::new();
11202        let mut selections_iter = selections.iter().peekable();
11203        while let Some(selection) = selections_iter.next() {
11204            let mut rows = selection.spanned_rows(false, &display_map);
11205            // duplicate line-wise
11206            if whole_lines || selection.start == selection.end {
11207                // Avoid duplicating the same lines twice.
11208                while let Some(next_selection) = selections_iter.peek() {
11209                    let next_rows = next_selection.spanned_rows(false, &display_map);
11210                    if next_rows.start < rows.end {
11211                        rows.end = next_rows.end;
11212                        selections_iter.next().unwrap();
11213                    } else {
11214                        break;
11215                    }
11216                }
11217
11218                // Copy the text from the selected row region and splice it either at the start
11219                // or end of the region.
11220                let start = Point::new(rows.start.0, 0);
11221                let end = Point::new(
11222                    rows.end.previous_row().0,
11223                    buffer.line_len(rows.end.previous_row()),
11224                );
11225                let text = buffer
11226                    .text_for_range(start..end)
11227                    .chain(Some("\n"))
11228                    .collect::<String>();
11229                let insert_location = if upwards {
11230                    Point::new(rows.end.0, 0)
11231                } else {
11232                    start
11233                };
11234                edits.push((insert_location..insert_location, text));
11235            } else {
11236                // duplicate character-wise
11237                let start = selection.start;
11238                let end = selection.end;
11239                let text = buffer.text_for_range(start..end).collect::<String>();
11240                edits.push((selection.end..selection.end, text));
11241            }
11242        }
11243
11244        self.transact(window, cx, |this, _, cx| {
11245            this.buffer.update(cx, |buffer, cx| {
11246                buffer.edit(edits, None, cx);
11247            });
11248
11249            this.request_autoscroll(Autoscroll::fit(), cx);
11250        });
11251    }
11252
11253    pub fn duplicate_line_up(
11254        &mut self,
11255        _: &DuplicateLineUp,
11256        window: &mut Window,
11257        cx: &mut Context<Self>,
11258    ) {
11259        self.duplicate(true, true, window, cx);
11260    }
11261
11262    pub fn duplicate_line_down(
11263        &mut self,
11264        _: &DuplicateLineDown,
11265        window: &mut Window,
11266        cx: &mut Context<Self>,
11267    ) {
11268        self.duplicate(false, true, window, cx);
11269    }
11270
11271    pub fn duplicate_selection(
11272        &mut self,
11273        _: &DuplicateSelection,
11274        window: &mut Window,
11275        cx: &mut Context<Self>,
11276    ) {
11277        self.duplicate(false, false, window, cx);
11278    }
11279
11280    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11281        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11282        if self.mode.is_single_line() {
11283            cx.propagate();
11284            return;
11285        }
11286
11287        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11288        let buffer = self.buffer.read(cx).snapshot(cx);
11289
11290        let mut edits = Vec::new();
11291        let mut unfold_ranges = Vec::new();
11292        let mut refold_creases = Vec::new();
11293
11294        let selections = self.selections.all::<Point>(cx);
11295        let mut selections = selections.iter().peekable();
11296        let mut contiguous_row_selections = Vec::new();
11297        let mut new_selections = Vec::new();
11298
11299        while let Some(selection) = selections.next() {
11300            // Find all the selections that span a contiguous row range
11301            let (start_row, end_row) = consume_contiguous_rows(
11302                &mut contiguous_row_selections,
11303                selection,
11304                &display_map,
11305                &mut selections,
11306            );
11307
11308            // Move the text spanned by the row range to be before the line preceding the row range
11309            if start_row.0 > 0 {
11310                let range_to_move = Point::new(
11311                    start_row.previous_row().0,
11312                    buffer.line_len(start_row.previous_row()),
11313                )
11314                    ..Point::new(
11315                        end_row.previous_row().0,
11316                        buffer.line_len(end_row.previous_row()),
11317                    );
11318                let insertion_point = display_map
11319                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11320                    .0;
11321
11322                // Don't move lines across excerpts
11323                if buffer
11324                    .excerpt_containing(insertion_point..range_to_move.end)
11325                    .is_some()
11326                {
11327                    let text = buffer
11328                        .text_for_range(range_to_move.clone())
11329                        .flat_map(|s| s.chars())
11330                        .skip(1)
11331                        .chain(['\n'])
11332                        .collect::<String>();
11333
11334                    edits.push((
11335                        buffer.anchor_after(range_to_move.start)
11336                            ..buffer.anchor_before(range_to_move.end),
11337                        String::new(),
11338                    ));
11339                    let insertion_anchor = buffer.anchor_after(insertion_point);
11340                    edits.push((insertion_anchor..insertion_anchor, text));
11341
11342                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11343
11344                    // Move selections up
11345                    new_selections.extend(contiguous_row_selections.drain(..).map(
11346                        |mut selection| {
11347                            selection.start.row -= row_delta;
11348                            selection.end.row -= row_delta;
11349                            selection
11350                        },
11351                    ));
11352
11353                    // Move folds up
11354                    unfold_ranges.push(range_to_move.clone());
11355                    for fold in display_map.folds_in_range(
11356                        buffer.anchor_before(range_to_move.start)
11357                            ..buffer.anchor_after(range_to_move.end),
11358                    ) {
11359                        let mut start = fold.range.start.to_point(&buffer);
11360                        let mut end = fold.range.end.to_point(&buffer);
11361                        start.row -= row_delta;
11362                        end.row -= row_delta;
11363                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11364                    }
11365                }
11366            }
11367
11368            // If we didn't move line(s), preserve the existing selections
11369            new_selections.append(&mut contiguous_row_selections);
11370        }
11371
11372        self.transact(window, cx, |this, window, cx| {
11373            this.unfold_ranges(&unfold_ranges, true, true, cx);
11374            this.buffer.update(cx, |buffer, cx| {
11375                for (range, text) in edits {
11376                    buffer.edit([(range, text)], None, cx);
11377                }
11378            });
11379            this.fold_creases(refold_creases, true, window, cx);
11380            this.change_selections(Default::default(), window, cx, |s| {
11381                s.select(new_selections);
11382            })
11383        });
11384    }
11385
11386    pub fn move_line_down(
11387        &mut self,
11388        _: &MoveLineDown,
11389        window: &mut Window,
11390        cx: &mut Context<Self>,
11391    ) {
11392        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11393        if self.mode.is_single_line() {
11394            cx.propagate();
11395            return;
11396        }
11397
11398        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11399        let buffer = self.buffer.read(cx).snapshot(cx);
11400
11401        let mut edits = Vec::new();
11402        let mut unfold_ranges = Vec::new();
11403        let mut refold_creases = Vec::new();
11404
11405        let selections = self.selections.all::<Point>(cx);
11406        let mut selections = selections.iter().peekable();
11407        let mut contiguous_row_selections = Vec::new();
11408        let mut new_selections = Vec::new();
11409
11410        while let Some(selection) = selections.next() {
11411            // Find all the selections that span a contiguous row range
11412            let (start_row, end_row) = consume_contiguous_rows(
11413                &mut contiguous_row_selections,
11414                selection,
11415                &display_map,
11416                &mut selections,
11417            );
11418
11419            // Move the text spanned by the row range to be after the last line of the row range
11420            if end_row.0 <= buffer.max_point().row {
11421                let range_to_move =
11422                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11423                let insertion_point = display_map
11424                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11425                    .0;
11426
11427                // Don't move lines across excerpt boundaries
11428                if buffer
11429                    .excerpt_containing(range_to_move.start..insertion_point)
11430                    .is_some()
11431                {
11432                    let mut text = String::from("\n");
11433                    text.extend(buffer.text_for_range(range_to_move.clone()));
11434                    text.pop(); // Drop trailing newline
11435                    edits.push((
11436                        buffer.anchor_after(range_to_move.start)
11437                            ..buffer.anchor_before(range_to_move.end),
11438                        String::new(),
11439                    ));
11440                    let insertion_anchor = buffer.anchor_after(insertion_point);
11441                    edits.push((insertion_anchor..insertion_anchor, text));
11442
11443                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11444
11445                    // Move selections down
11446                    new_selections.extend(contiguous_row_selections.drain(..).map(
11447                        |mut selection| {
11448                            selection.start.row += row_delta;
11449                            selection.end.row += row_delta;
11450                            selection
11451                        },
11452                    ));
11453
11454                    // Move folds down
11455                    unfold_ranges.push(range_to_move.clone());
11456                    for fold in display_map.folds_in_range(
11457                        buffer.anchor_before(range_to_move.start)
11458                            ..buffer.anchor_after(range_to_move.end),
11459                    ) {
11460                        let mut start = fold.range.start.to_point(&buffer);
11461                        let mut end = fold.range.end.to_point(&buffer);
11462                        start.row += row_delta;
11463                        end.row += row_delta;
11464                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11465                    }
11466                }
11467            }
11468
11469            // If we didn't move line(s), preserve the existing selections
11470            new_selections.append(&mut contiguous_row_selections);
11471        }
11472
11473        self.transact(window, cx, |this, window, cx| {
11474            this.unfold_ranges(&unfold_ranges, true, true, cx);
11475            this.buffer.update(cx, |buffer, cx| {
11476                for (range, text) in edits {
11477                    buffer.edit([(range, text)], None, cx);
11478                }
11479            });
11480            this.fold_creases(refold_creases, true, window, cx);
11481            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11482        });
11483    }
11484
11485    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11487        let text_layout_details = &self.text_layout_details(window);
11488        self.transact(window, cx, |this, window, cx| {
11489            let edits = this.change_selections(Default::default(), window, cx, |s| {
11490                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11491                s.move_with(|display_map, selection| {
11492                    if !selection.is_empty() {
11493                        return;
11494                    }
11495
11496                    let mut head = selection.head();
11497                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11498                    if head.column() == display_map.line_len(head.row()) {
11499                        transpose_offset = display_map
11500                            .buffer_snapshot
11501                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11502                    }
11503
11504                    if transpose_offset == 0 {
11505                        return;
11506                    }
11507
11508                    *head.column_mut() += 1;
11509                    head = display_map.clip_point(head, Bias::Right);
11510                    let goal = SelectionGoal::HorizontalPosition(
11511                        display_map
11512                            .x_for_display_point(head, text_layout_details)
11513                            .into(),
11514                    );
11515                    selection.collapse_to(head, goal);
11516
11517                    let transpose_start = display_map
11518                        .buffer_snapshot
11519                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11520                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11521                        let transpose_end = display_map
11522                            .buffer_snapshot
11523                            .clip_offset(transpose_offset + 1, Bias::Right);
11524                        if let Some(ch) =
11525                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11526                        {
11527                            edits.push((transpose_start..transpose_offset, String::new()));
11528                            edits.push((transpose_end..transpose_end, ch.to_string()));
11529                        }
11530                    }
11531                });
11532                edits
11533            });
11534            this.buffer
11535                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11536            let selections = this.selections.all::<usize>(cx);
11537            this.change_selections(Default::default(), window, cx, |s| {
11538                s.select(selections);
11539            });
11540        });
11541    }
11542
11543    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11544        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11545        if self.mode.is_single_line() {
11546            cx.propagate();
11547            return;
11548        }
11549
11550        self.rewrap_impl(RewrapOptions::default(), cx)
11551    }
11552
11553    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11554        let buffer = self.buffer.read(cx).snapshot(cx);
11555        let selections = self.selections.all::<Point>(cx);
11556
11557        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11558        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11559            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11560                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11561                .peekable();
11562
11563            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11564                row
11565            } else {
11566                return Vec::new();
11567            };
11568
11569            let language_settings = buffer.language_settings_at(selection.head(), cx);
11570            let language_scope = buffer.language_scope_at(selection.head());
11571
11572            let indent_and_prefix_for_row =
11573                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11574                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11575                    let (comment_prefix, rewrap_prefix) =
11576                        if let Some(language_scope) = &language_scope {
11577                            let indent_end = Point::new(row, indent.len);
11578                            let comment_prefix = language_scope
11579                                .line_comment_prefixes()
11580                                .iter()
11581                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11582                                .map(|prefix| prefix.to_string());
11583                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11584                            let line_text_after_indent = buffer
11585                                .text_for_range(indent_end..line_end)
11586                                .collect::<String>();
11587                            let rewrap_prefix = language_scope
11588                                .rewrap_prefixes()
11589                                .iter()
11590                                .find_map(|prefix_regex| {
11591                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11592                                        if mat.start() == 0 {
11593                                            Some(mat.as_str().to_string())
11594                                        } else {
11595                                            None
11596                                        }
11597                                    })
11598                                })
11599                                .flatten();
11600                            (comment_prefix, rewrap_prefix)
11601                        } else {
11602                            (None, None)
11603                        };
11604                    (indent, comment_prefix, rewrap_prefix)
11605                };
11606
11607            let mut ranges = Vec::new();
11608            let from_empty_selection = selection.is_empty();
11609
11610            let mut current_range_start = first_row;
11611            let mut prev_row = first_row;
11612            let (
11613                mut current_range_indent,
11614                mut current_range_comment_prefix,
11615                mut current_range_rewrap_prefix,
11616            ) = indent_and_prefix_for_row(first_row);
11617
11618            for row in non_blank_rows_iter.skip(1) {
11619                let has_paragraph_break = row > prev_row + 1;
11620
11621                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11622                    indent_and_prefix_for_row(row);
11623
11624                let has_indent_change = row_indent != current_range_indent;
11625                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11626
11627                let has_boundary_change = has_comment_change
11628                    || row_rewrap_prefix.is_some()
11629                    || (has_indent_change && current_range_comment_prefix.is_some());
11630
11631                if has_paragraph_break || has_boundary_change {
11632                    ranges.push((
11633                        language_settings.clone(),
11634                        Point::new(current_range_start, 0)
11635                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11636                        current_range_indent,
11637                        current_range_comment_prefix.clone(),
11638                        current_range_rewrap_prefix.clone(),
11639                        from_empty_selection,
11640                    ));
11641                    current_range_start = row;
11642                    current_range_indent = row_indent;
11643                    current_range_comment_prefix = row_comment_prefix;
11644                    current_range_rewrap_prefix = row_rewrap_prefix;
11645                }
11646                prev_row = row;
11647            }
11648
11649            ranges.push((
11650                language_settings.clone(),
11651                Point::new(current_range_start, 0)
11652                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11653                current_range_indent,
11654                current_range_comment_prefix,
11655                current_range_rewrap_prefix,
11656                from_empty_selection,
11657            ));
11658
11659            ranges
11660        });
11661
11662        let mut edits = Vec::new();
11663        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11664
11665        for (
11666            language_settings,
11667            wrap_range,
11668            indent_size,
11669            comment_prefix,
11670            rewrap_prefix,
11671            from_empty_selection,
11672        ) in wrap_ranges
11673        {
11674            let mut start_row = wrap_range.start.row;
11675            let mut end_row = wrap_range.end.row;
11676
11677            // Skip selections that overlap with a range that has already been rewrapped.
11678            let selection_range = start_row..end_row;
11679            if rewrapped_row_ranges
11680                .iter()
11681                .any(|range| range.overlaps(&selection_range))
11682            {
11683                continue;
11684            }
11685
11686            let tab_size = language_settings.tab_size;
11687
11688            let indent_prefix = indent_size.chars().collect::<String>();
11689            let mut line_prefix = indent_prefix.clone();
11690            let mut inside_comment = false;
11691            if let Some(prefix) = &comment_prefix {
11692                line_prefix.push_str(prefix);
11693                inside_comment = true;
11694            }
11695            if let Some(prefix) = &rewrap_prefix {
11696                line_prefix.push_str(prefix);
11697            }
11698
11699            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11700                RewrapBehavior::InComments => inside_comment,
11701                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11702                RewrapBehavior::Anywhere => true,
11703            };
11704
11705            let should_rewrap = options.override_language_settings
11706                || allow_rewrap_based_on_language
11707                || self.hard_wrap.is_some();
11708            if !should_rewrap {
11709                continue;
11710            }
11711
11712            if from_empty_selection {
11713                'expand_upwards: while start_row > 0 {
11714                    let prev_row = start_row - 1;
11715                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11716                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11717                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11718                    {
11719                        start_row = prev_row;
11720                    } else {
11721                        break 'expand_upwards;
11722                    }
11723                }
11724
11725                'expand_downwards: while end_row < buffer.max_point().row {
11726                    let next_row = end_row + 1;
11727                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11728                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11729                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11730                    {
11731                        end_row = next_row;
11732                    } else {
11733                        break 'expand_downwards;
11734                    }
11735                }
11736            }
11737
11738            let start = Point::new(start_row, 0);
11739            let start_offset = start.to_offset(&buffer);
11740            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11741            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11742            let Some(lines_without_prefixes) = selection_text
11743                .lines()
11744                .enumerate()
11745                .map(|(ix, line)| {
11746                    let line_trimmed = line.trim_start();
11747                    if rewrap_prefix.is_some() && ix > 0 {
11748                        Ok(line_trimmed)
11749                    } else {
11750                        line_trimmed
11751                            .strip_prefix(&line_prefix.trim_start())
11752                            .with_context(|| {
11753                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11754                            })
11755                    }
11756                })
11757                .collect::<Result<Vec<_>, _>>()
11758                .log_err()
11759            else {
11760                continue;
11761            };
11762
11763            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11764                buffer
11765                    .language_settings_at(Point::new(start_row, 0), cx)
11766                    .preferred_line_length as usize
11767            });
11768
11769            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11770                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11771            } else {
11772                line_prefix.clone()
11773            };
11774
11775            let wrapped_text = wrap_with_prefix(
11776                line_prefix,
11777                subsequent_lines_prefix,
11778                lines_without_prefixes.join("\n"),
11779                wrap_column,
11780                tab_size,
11781                options.preserve_existing_whitespace,
11782            );
11783
11784            // TODO: should always use char-based diff while still supporting cursor behavior that
11785            // matches vim.
11786            let mut diff_options = DiffOptions::default();
11787            if options.override_language_settings {
11788                diff_options.max_word_diff_len = 0;
11789                diff_options.max_word_diff_line_count = 0;
11790            } else {
11791                diff_options.max_word_diff_len = usize::MAX;
11792                diff_options.max_word_diff_line_count = usize::MAX;
11793            }
11794
11795            for (old_range, new_text) in
11796                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11797            {
11798                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11799                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11800                edits.push((edit_start..edit_end, new_text));
11801            }
11802
11803            rewrapped_row_ranges.push(start_row..=end_row);
11804        }
11805
11806        self.buffer
11807            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11808    }
11809
11810    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11811        let mut text = String::new();
11812        let buffer = self.buffer.read(cx).snapshot(cx);
11813        let mut selections = self.selections.all::<Point>(cx);
11814        let mut clipboard_selections = Vec::with_capacity(selections.len());
11815        {
11816            let max_point = buffer.max_point();
11817            let mut is_first = true;
11818            for selection in &mut selections {
11819                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11820                if is_entire_line {
11821                    selection.start = Point::new(selection.start.row, 0);
11822                    if !selection.is_empty() && selection.end.column == 0 {
11823                        selection.end = cmp::min(max_point, selection.end);
11824                    } else {
11825                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11826                    }
11827                    selection.goal = SelectionGoal::None;
11828                }
11829                if is_first {
11830                    is_first = false;
11831                } else {
11832                    text += "\n";
11833                }
11834                let mut len = 0;
11835                for chunk in buffer.text_for_range(selection.start..selection.end) {
11836                    text.push_str(chunk);
11837                    len += chunk.len();
11838                }
11839                clipboard_selections.push(ClipboardSelection {
11840                    len,
11841                    is_entire_line,
11842                    first_line_indent: buffer
11843                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11844                        .len,
11845                });
11846            }
11847        }
11848
11849        self.transact(window, cx, |this, window, cx| {
11850            this.change_selections(Default::default(), window, cx, |s| {
11851                s.select(selections);
11852            });
11853            this.insert("", window, cx);
11854        });
11855        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11856    }
11857
11858    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11859        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11860        let item = self.cut_common(window, cx);
11861        cx.write_to_clipboard(item);
11862    }
11863
11864    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11865        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11866        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11867            s.move_with(|snapshot, sel| {
11868                if sel.is_empty() {
11869                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11870                }
11871            });
11872        });
11873        let item = self.cut_common(window, cx);
11874        cx.set_global(KillRing(item))
11875    }
11876
11877    pub fn kill_ring_yank(
11878        &mut self,
11879        _: &KillRingYank,
11880        window: &mut Window,
11881        cx: &mut Context<Self>,
11882    ) {
11883        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11884        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11885            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11886                (kill_ring.text().to_string(), kill_ring.metadata_json())
11887            } else {
11888                return;
11889            }
11890        } else {
11891            return;
11892        };
11893        self.do_paste(&text, metadata, false, window, cx);
11894    }
11895
11896    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11897        self.do_copy(true, cx);
11898    }
11899
11900    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11901        self.do_copy(false, cx);
11902    }
11903
11904    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11905        let selections = self.selections.all::<Point>(cx);
11906        let buffer = self.buffer.read(cx).read(cx);
11907        let mut text = String::new();
11908
11909        let mut clipboard_selections = Vec::with_capacity(selections.len());
11910        {
11911            let max_point = buffer.max_point();
11912            let mut is_first = true;
11913            for selection in &selections {
11914                let mut start = selection.start;
11915                let mut end = selection.end;
11916                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11917                if is_entire_line {
11918                    start = Point::new(start.row, 0);
11919                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11920                }
11921
11922                let mut trimmed_selections = Vec::new();
11923                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11924                    let row = MultiBufferRow(start.row);
11925                    let first_indent = buffer.indent_size_for_line(row);
11926                    if first_indent.len == 0 || start.column > first_indent.len {
11927                        trimmed_selections.push(start..end);
11928                    } else {
11929                        trimmed_selections.push(
11930                            Point::new(row.0, first_indent.len)
11931                                ..Point::new(row.0, buffer.line_len(row)),
11932                        );
11933                        for row in start.row + 1..=end.row {
11934                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11935                            if row == end.row {
11936                                line_len = end.column;
11937                            }
11938                            if line_len == 0 {
11939                                trimmed_selections
11940                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11941                                continue;
11942                            }
11943                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11944                            if row_indent_size.len >= first_indent.len {
11945                                trimmed_selections.push(
11946                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11947                                );
11948                            } else {
11949                                trimmed_selections.clear();
11950                                trimmed_selections.push(start..end);
11951                                break;
11952                            }
11953                        }
11954                    }
11955                } else {
11956                    trimmed_selections.push(start..end);
11957                }
11958
11959                for trimmed_range in trimmed_selections {
11960                    if is_first {
11961                        is_first = false;
11962                    } else {
11963                        text += "\n";
11964                    }
11965                    let mut len = 0;
11966                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11967                        text.push_str(chunk);
11968                        len += chunk.len();
11969                    }
11970                    clipboard_selections.push(ClipboardSelection {
11971                        len,
11972                        is_entire_line,
11973                        first_line_indent: buffer
11974                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11975                            .len,
11976                    });
11977                }
11978            }
11979        }
11980
11981        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11982            text,
11983            clipboard_selections,
11984        ));
11985    }
11986
11987    pub fn do_paste(
11988        &mut self,
11989        text: &String,
11990        clipboard_selections: Option<Vec<ClipboardSelection>>,
11991        handle_entire_lines: bool,
11992        window: &mut Window,
11993        cx: &mut Context<Self>,
11994    ) {
11995        if self.read_only(cx) {
11996            return;
11997        }
11998
11999        let clipboard_text = Cow::Borrowed(text);
12000
12001        self.transact(window, cx, |this, window, cx| {
12002            if let Some(mut clipboard_selections) = clipboard_selections {
12003                let old_selections = this.selections.all::<usize>(cx);
12004                let all_selections_were_entire_line =
12005                    clipboard_selections.iter().all(|s| s.is_entire_line);
12006                let first_selection_indent_column =
12007                    clipboard_selections.first().map(|s| s.first_line_indent);
12008                if clipboard_selections.len() != old_selections.len() {
12009                    clipboard_selections.drain(..);
12010                }
12011                let cursor_offset = this.selections.last::<usize>(cx).head();
12012                let mut auto_indent_on_paste = true;
12013
12014                this.buffer.update(cx, |buffer, cx| {
12015                    let snapshot = buffer.read(cx);
12016                    auto_indent_on_paste = snapshot
12017                        .language_settings_at(cursor_offset, cx)
12018                        .auto_indent_on_paste;
12019
12020                    let mut start_offset = 0;
12021                    let mut edits = Vec::new();
12022                    let mut original_indent_columns = Vec::new();
12023                    for (ix, selection) in old_selections.iter().enumerate() {
12024                        let to_insert;
12025                        let entire_line;
12026                        let original_indent_column;
12027                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12028                            let end_offset = start_offset + clipboard_selection.len;
12029                            to_insert = &clipboard_text[start_offset..end_offset];
12030                            entire_line = clipboard_selection.is_entire_line;
12031                            start_offset = end_offset + 1;
12032                            original_indent_column = Some(clipboard_selection.first_line_indent);
12033                        } else {
12034                            to_insert = clipboard_text.as_str();
12035                            entire_line = all_selections_were_entire_line;
12036                            original_indent_column = first_selection_indent_column
12037                        }
12038
12039                        // If the corresponding selection was empty when this slice of the
12040                        // clipboard text was written, then the entire line containing the
12041                        // selection was copied. If this selection is also currently empty,
12042                        // then paste the line before the current line of the buffer.
12043                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12044                            let column = selection.start.to_point(&snapshot).column as usize;
12045                            let line_start = selection.start - column;
12046                            line_start..line_start
12047                        } else {
12048                            selection.range()
12049                        };
12050
12051                        edits.push((range, to_insert));
12052                        original_indent_columns.push(original_indent_column);
12053                    }
12054                    drop(snapshot);
12055
12056                    buffer.edit(
12057                        edits,
12058                        if auto_indent_on_paste {
12059                            Some(AutoindentMode::Block {
12060                                original_indent_columns,
12061                            })
12062                        } else {
12063                            None
12064                        },
12065                        cx,
12066                    );
12067                });
12068
12069                let selections = this.selections.all::<usize>(cx);
12070                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12071            } else {
12072                this.insert(&clipboard_text, window, cx);
12073            }
12074        });
12075    }
12076
12077    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12078        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12079        if let Some(item) = cx.read_from_clipboard() {
12080            let entries = item.entries();
12081
12082            match entries.first() {
12083                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12084                // of all the pasted entries.
12085                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12086                    .do_paste(
12087                        clipboard_string.text(),
12088                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12089                        true,
12090                        window,
12091                        cx,
12092                    ),
12093                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12094            }
12095        }
12096    }
12097
12098    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12099        if self.read_only(cx) {
12100            return;
12101        }
12102
12103        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12104
12105        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12106            if let Some((selections, _)) =
12107                self.selection_history.transaction(transaction_id).cloned()
12108            {
12109                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12110                    s.select_anchors(selections.to_vec());
12111                });
12112            } else {
12113                log::error!(
12114                    "No entry in selection_history found for undo. \
12115                     This may correspond to a bug where undo does not update the selection. \
12116                     If this is occurring, please add details to \
12117                     https://github.com/zed-industries/zed/issues/22692"
12118                );
12119            }
12120            self.request_autoscroll(Autoscroll::fit(), cx);
12121            self.unmark_text(window, cx);
12122            self.refresh_inline_completion(true, false, window, cx);
12123            cx.emit(EditorEvent::Edited { transaction_id });
12124            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12125        }
12126    }
12127
12128    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12129        if self.read_only(cx) {
12130            return;
12131        }
12132
12133        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12134
12135        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12136            if let Some((_, Some(selections))) =
12137                self.selection_history.transaction(transaction_id).cloned()
12138            {
12139                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12140                    s.select_anchors(selections.to_vec());
12141                });
12142            } else {
12143                log::error!(
12144                    "No entry in selection_history found for redo. \
12145                     This may correspond to a bug where undo does not update the selection. \
12146                     If this is occurring, please add details to \
12147                     https://github.com/zed-industries/zed/issues/22692"
12148                );
12149            }
12150            self.request_autoscroll(Autoscroll::fit(), cx);
12151            self.unmark_text(window, cx);
12152            self.refresh_inline_completion(true, false, window, cx);
12153            cx.emit(EditorEvent::Edited { transaction_id });
12154        }
12155    }
12156
12157    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12158        self.buffer
12159            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12160    }
12161
12162    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12163        self.buffer
12164            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12165    }
12166
12167    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12169        self.change_selections(Default::default(), window, cx, |s| {
12170            s.move_with(|map, selection| {
12171                let cursor = if selection.is_empty() {
12172                    movement::left(map, selection.start)
12173                } else {
12174                    selection.start
12175                };
12176                selection.collapse_to(cursor, SelectionGoal::None);
12177            });
12178        })
12179    }
12180
12181    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12183        self.change_selections(Default::default(), window, cx, |s| {
12184            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12185        })
12186    }
12187
12188    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12190        self.change_selections(Default::default(), window, cx, |s| {
12191            s.move_with(|map, selection| {
12192                let cursor = if selection.is_empty() {
12193                    movement::right(map, selection.end)
12194                } else {
12195                    selection.end
12196                };
12197                selection.collapse_to(cursor, SelectionGoal::None)
12198            });
12199        })
12200    }
12201
12202    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12204        self.change_selections(Default::default(), window, cx, |s| {
12205            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12206        })
12207    }
12208
12209    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12210        if self.take_rename(true, window, cx).is_some() {
12211            return;
12212        }
12213
12214        if self.mode.is_single_line() {
12215            cx.propagate();
12216            return;
12217        }
12218
12219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12220
12221        let text_layout_details = &self.text_layout_details(window);
12222        let selection_count = self.selections.count();
12223        let first_selection = self.selections.first_anchor();
12224
12225        self.change_selections(Default::default(), window, cx, |s| {
12226            s.move_with(|map, selection| {
12227                if !selection.is_empty() {
12228                    selection.goal = SelectionGoal::None;
12229                }
12230                let (cursor, goal) = movement::up(
12231                    map,
12232                    selection.start,
12233                    selection.goal,
12234                    false,
12235                    text_layout_details,
12236                );
12237                selection.collapse_to(cursor, goal);
12238            });
12239        });
12240
12241        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12242        {
12243            cx.propagate();
12244        }
12245    }
12246
12247    pub fn move_up_by_lines(
12248        &mut self,
12249        action: &MoveUpByLines,
12250        window: &mut Window,
12251        cx: &mut Context<Self>,
12252    ) {
12253        if self.take_rename(true, window, cx).is_some() {
12254            return;
12255        }
12256
12257        if self.mode.is_single_line() {
12258            cx.propagate();
12259            return;
12260        }
12261
12262        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12263
12264        let text_layout_details = &self.text_layout_details(window);
12265
12266        self.change_selections(Default::default(), window, cx, |s| {
12267            s.move_with(|map, selection| {
12268                if !selection.is_empty() {
12269                    selection.goal = SelectionGoal::None;
12270                }
12271                let (cursor, goal) = movement::up_by_rows(
12272                    map,
12273                    selection.start,
12274                    action.lines,
12275                    selection.goal,
12276                    false,
12277                    text_layout_details,
12278                );
12279                selection.collapse_to(cursor, goal);
12280            });
12281        })
12282    }
12283
12284    pub fn move_down_by_lines(
12285        &mut self,
12286        action: &MoveDownByLines,
12287        window: &mut Window,
12288        cx: &mut Context<Self>,
12289    ) {
12290        if self.take_rename(true, window, cx).is_some() {
12291            return;
12292        }
12293
12294        if self.mode.is_single_line() {
12295            cx.propagate();
12296            return;
12297        }
12298
12299        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12300
12301        let text_layout_details = &self.text_layout_details(window);
12302
12303        self.change_selections(Default::default(), window, cx, |s| {
12304            s.move_with(|map, selection| {
12305                if !selection.is_empty() {
12306                    selection.goal = SelectionGoal::None;
12307                }
12308                let (cursor, goal) = movement::down_by_rows(
12309                    map,
12310                    selection.start,
12311                    action.lines,
12312                    selection.goal,
12313                    false,
12314                    text_layout_details,
12315                );
12316                selection.collapse_to(cursor, goal);
12317            });
12318        })
12319    }
12320
12321    pub fn select_down_by_lines(
12322        &mut self,
12323        action: &SelectDownByLines,
12324        window: &mut Window,
12325        cx: &mut Context<Self>,
12326    ) {
12327        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12328        let text_layout_details = &self.text_layout_details(window);
12329        self.change_selections(Default::default(), window, cx, |s| {
12330            s.move_heads_with(|map, head, goal| {
12331                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12332            })
12333        })
12334    }
12335
12336    pub fn select_up_by_lines(
12337        &mut self,
12338        action: &SelectUpByLines,
12339        window: &mut Window,
12340        cx: &mut Context<Self>,
12341    ) {
12342        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12343        let text_layout_details = &self.text_layout_details(window);
12344        self.change_selections(Default::default(), window, cx, |s| {
12345            s.move_heads_with(|map, head, goal| {
12346                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12347            })
12348        })
12349    }
12350
12351    pub fn select_page_up(
12352        &mut self,
12353        _: &SelectPageUp,
12354        window: &mut Window,
12355        cx: &mut Context<Self>,
12356    ) {
12357        let Some(row_count) = self.visible_row_count() else {
12358            return;
12359        };
12360
12361        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12362
12363        let text_layout_details = &self.text_layout_details(window);
12364
12365        self.change_selections(Default::default(), window, cx, |s| {
12366            s.move_heads_with(|map, head, goal| {
12367                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12368            })
12369        })
12370    }
12371
12372    pub fn move_page_up(
12373        &mut self,
12374        action: &MovePageUp,
12375        window: &mut Window,
12376        cx: &mut Context<Self>,
12377    ) {
12378        if self.take_rename(true, window, cx).is_some() {
12379            return;
12380        }
12381
12382        if self
12383            .context_menu
12384            .borrow_mut()
12385            .as_mut()
12386            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12387            .unwrap_or(false)
12388        {
12389            return;
12390        }
12391
12392        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12393            cx.propagate();
12394            return;
12395        }
12396
12397        let Some(row_count) = self.visible_row_count() else {
12398            return;
12399        };
12400
12401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12402
12403        let effects = if action.center_cursor {
12404            SelectionEffects::scroll(Autoscroll::center())
12405        } else {
12406            SelectionEffects::default()
12407        };
12408
12409        let text_layout_details = &self.text_layout_details(window);
12410
12411        self.change_selections(effects, window, cx, |s| {
12412            s.move_with(|map, selection| {
12413                if !selection.is_empty() {
12414                    selection.goal = SelectionGoal::None;
12415                }
12416                let (cursor, goal) = movement::up_by_rows(
12417                    map,
12418                    selection.end,
12419                    row_count,
12420                    selection.goal,
12421                    false,
12422                    text_layout_details,
12423                );
12424                selection.collapse_to(cursor, goal);
12425            });
12426        });
12427    }
12428
12429    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12430        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12431        let text_layout_details = &self.text_layout_details(window);
12432        self.change_selections(Default::default(), window, cx, |s| {
12433            s.move_heads_with(|map, head, goal| {
12434                movement::up(map, head, goal, false, text_layout_details)
12435            })
12436        })
12437    }
12438
12439    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12440        self.take_rename(true, window, cx);
12441
12442        if self.mode.is_single_line() {
12443            cx.propagate();
12444            return;
12445        }
12446
12447        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12448
12449        let text_layout_details = &self.text_layout_details(window);
12450        let selection_count = self.selections.count();
12451        let first_selection = self.selections.first_anchor();
12452
12453        self.change_selections(Default::default(), window, cx, |s| {
12454            s.move_with(|map, selection| {
12455                if !selection.is_empty() {
12456                    selection.goal = SelectionGoal::None;
12457                }
12458                let (cursor, goal) = movement::down(
12459                    map,
12460                    selection.end,
12461                    selection.goal,
12462                    false,
12463                    text_layout_details,
12464                );
12465                selection.collapse_to(cursor, goal);
12466            });
12467        });
12468
12469        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12470        {
12471            cx.propagate();
12472        }
12473    }
12474
12475    pub fn select_page_down(
12476        &mut self,
12477        _: &SelectPageDown,
12478        window: &mut Window,
12479        cx: &mut Context<Self>,
12480    ) {
12481        let Some(row_count) = self.visible_row_count() else {
12482            return;
12483        };
12484
12485        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12486
12487        let text_layout_details = &self.text_layout_details(window);
12488
12489        self.change_selections(Default::default(), window, cx, |s| {
12490            s.move_heads_with(|map, head, goal| {
12491                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12492            })
12493        })
12494    }
12495
12496    pub fn move_page_down(
12497        &mut self,
12498        action: &MovePageDown,
12499        window: &mut Window,
12500        cx: &mut Context<Self>,
12501    ) {
12502        if self.take_rename(true, window, cx).is_some() {
12503            return;
12504        }
12505
12506        if self
12507            .context_menu
12508            .borrow_mut()
12509            .as_mut()
12510            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12511            .unwrap_or(false)
12512        {
12513            return;
12514        }
12515
12516        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12517            cx.propagate();
12518            return;
12519        }
12520
12521        let Some(row_count) = self.visible_row_count() else {
12522            return;
12523        };
12524
12525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12526
12527        let effects = if action.center_cursor {
12528            SelectionEffects::scroll(Autoscroll::center())
12529        } else {
12530            SelectionEffects::default()
12531        };
12532
12533        let text_layout_details = &self.text_layout_details(window);
12534        self.change_selections(effects, window, cx, |s| {
12535            s.move_with(|map, selection| {
12536                if !selection.is_empty() {
12537                    selection.goal = SelectionGoal::None;
12538                }
12539                let (cursor, goal) = movement::down_by_rows(
12540                    map,
12541                    selection.end,
12542                    row_count,
12543                    selection.goal,
12544                    false,
12545                    text_layout_details,
12546                );
12547                selection.collapse_to(cursor, goal);
12548            });
12549        });
12550    }
12551
12552    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12553        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12554        let text_layout_details = &self.text_layout_details(window);
12555        self.change_selections(Default::default(), window, cx, |s| {
12556            s.move_heads_with(|map, head, goal| {
12557                movement::down(map, head, goal, false, text_layout_details)
12558            })
12559        });
12560    }
12561
12562    pub fn context_menu_first(
12563        &mut self,
12564        _: &ContextMenuFirst,
12565        window: &mut Window,
12566        cx: &mut Context<Self>,
12567    ) {
12568        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12569            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12570        }
12571    }
12572
12573    pub fn context_menu_prev(
12574        &mut self,
12575        _: &ContextMenuPrevious,
12576        window: &mut Window,
12577        cx: &mut Context<Self>,
12578    ) {
12579        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12580            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12581        }
12582    }
12583
12584    pub fn context_menu_next(
12585        &mut self,
12586        _: &ContextMenuNext,
12587        window: &mut Window,
12588        cx: &mut Context<Self>,
12589    ) {
12590        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12591            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12592        }
12593    }
12594
12595    pub fn context_menu_last(
12596        &mut self,
12597        _: &ContextMenuLast,
12598        window: &mut Window,
12599        cx: &mut Context<Self>,
12600    ) {
12601        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12602            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12603        }
12604    }
12605
12606    pub fn signature_help_prev(
12607        &mut self,
12608        _: &SignatureHelpPrevious,
12609        _: &mut Window,
12610        cx: &mut Context<Self>,
12611    ) {
12612        if let Some(popover) = self.signature_help_state.popover_mut() {
12613            if popover.current_signature == 0 {
12614                popover.current_signature = popover.signatures.len() - 1;
12615            } else {
12616                popover.current_signature -= 1;
12617            }
12618            cx.notify();
12619        }
12620    }
12621
12622    pub fn signature_help_next(
12623        &mut self,
12624        _: &SignatureHelpNext,
12625        _: &mut Window,
12626        cx: &mut Context<Self>,
12627    ) {
12628        if let Some(popover) = self.signature_help_state.popover_mut() {
12629            if popover.current_signature + 1 == popover.signatures.len() {
12630                popover.current_signature = 0;
12631            } else {
12632                popover.current_signature += 1;
12633            }
12634            cx.notify();
12635        }
12636    }
12637
12638    pub fn move_to_previous_word_start(
12639        &mut self,
12640        _: &MoveToPreviousWordStart,
12641        window: &mut Window,
12642        cx: &mut Context<Self>,
12643    ) {
12644        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12645        self.change_selections(Default::default(), window, cx, |s| {
12646            s.move_cursors_with(|map, head, _| {
12647                (
12648                    movement::previous_word_start(map, head),
12649                    SelectionGoal::None,
12650                )
12651            });
12652        })
12653    }
12654
12655    pub fn move_to_previous_subword_start(
12656        &mut self,
12657        _: &MoveToPreviousSubwordStart,
12658        window: &mut Window,
12659        cx: &mut Context<Self>,
12660    ) {
12661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12662        self.change_selections(Default::default(), window, cx, |s| {
12663            s.move_cursors_with(|map, head, _| {
12664                (
12665                    movement::previous_subword_start(map, head),
12666                    SelectionGoal::None,
12667                )
12668            });
12669        })
12670    }
12671
12672    pub fn select_to_previous_word_start(
12673        &mut self,
12674        _: &SelectToPreviousWordStart,
12675        window: &mut Window,
12676        cx: &mut Context<Self>,
12677    ) {
12678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12679        self.change_selections(Default::default(), window, cx, |s| {
12680            s.move_heads_with(|map, head, _| {
12681                (
12682                    movement::previous_word_start(map, head),
12683                    SelectionGoal::None,
12684                )
12685            });
12686        })
12687    }
12688
12689    pub fn select_to_previous_subword_start(
12690        &mut self,
12691        _: &SelectToPreviousSubwordStart,
12692        window: &mut Window,
12693        cx: &mut Context<Self>,
12694    ) {
12695        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12696        self.change_selections(Default::default(), window, cx, |s| {
12697            s.move_heads_with(|map, head, _| {
12698                (
12699                    movement::previous_subword_start(map, head),
12700                    SelectionGoal::None,
12701                )
12702            });
12703        })
12704    }
12705
12706    pub fn delete_to_previous_word_start(
12707        &mut self,
12708        action: &DeleteToPreviousWordStart,
12709        window: &mut Window,
12710        cx: &mut Context<Self>,
12711    ) {
12712        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12713        self.transact(window, cx, |this, window, cx| {
12714            this.select_autoclose_pair(window, cx);
12715            this.change_selections(Default::default(), window, cx, |s| {
12716                s.move_with(|map, selection| {
12717                    if selection.is_empty() {
12718                        let cursor = if action.ignore_newlines {
12719                            movement::previous_word_start(map, selection.head())
12720                        } else {
12721                            movement::previous_word_start_or_newline(map, selection.head())
12722                        };
12723                        selection.set_head(cursor, SelectionGoal::None);
12724                    }
12725                });
12726            });
12727            this.insert("", window, cx);
12728        });
12729    }
12730
12731    pub fn delete_to_previous_subword_start(
12732        &mut self,
12733        _: &DeleteToPreviousSubwordStart,
12734        window: &mut Window,
12735        cx: &mut Context<Self>,
12736    ) {
12737        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12738        self.transact(window, cx, |this, window, cx| {
12739            this.select_autoclose_pair(window, cx);
12740            this.change_selections(Default::default(), window, cx, |s| {
12741                s.move_with(|map, selection| {
12742                    if selection.is_empty() {
12743                        let cursor = movement::previous_subword_start(map, selection.head());
12744                        selection.set_head(cursor, SelectionGoal::None);
12745                    }
12746                });
12747            });
12748            this.insert("", window, cx);
12749        });
12750    }
12751
12752    pub fn move_to_next_word_end(
12753        &mut self,
12754        _: &MoveToNextWordEnd,
12755        window: &mut Window,
12756        cx: &mut Context<Self>,
12757    ) {
12758        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12759        self.change_selections(Default::default(), window, cx, |s| {
12760            s.move_cursors_with(|map, head, _| {
12761                (movement::next_word_end(map, head), SelectionGoal::None)
12762            });
12763        })
12764    }
12765
12766    pub fn move_to_next_subword_end(
12767        &mut self,
12768        _: &MoveToNextSubwordEnd,
12769        window: &mut Window,
12770        cx: &mut Context<Self>,
12771    ) {
12772        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12773        self.change_selections(Default::default(), window, cx, |s| {
12774            s.move_cursors_with(|map, head, _| {
12775                (movement::next_subword_end(map, head), SelectionGoal::None)
12776            });
12777        })
12778    }
12779
12780    pub fn select_to_next_word_end(
12781        &mut self,
12782        _: &SelectToNextWordEnd,
12783        window: &mut Window,
12784        cx: &mut Context<Self>,
12785    ) {
12786        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12787        self.change_selections(Default::default(), window, cx, |s| {
12788            s.move_heads_with(|map, head, _| {
12789                (movement::next_word_end(map, head), SelectionGoal::None)
12790            });
12791        })
12792    }
12793
12794    pub fn select_to_next_subword_end(
12795        &mut self,
12796        _: &SelectToNextSubwordEnd,
12797        window: &mut Window,
12798        cx: &mut Context<Self>,
12799    ) {
12800        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12801        self.change_selections(Default::default(), window, cx, |s| {
12802            s.move_heads_with(|map, head, _| {
12803                (movement::next_subword_end(map, head), SelectionGoal::None)
12804            });
12805        })
12806    }
12807
12808    pub fn delete_to_next_word_end(
12809        &mut self,
12810        action: &DeleteToNextWordEnd,
12811        window: &mut Window,
12812        cx: &mut Context<Self>,
12813    ) {
12814        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12815        self.transact(window, cx, |this, window, cx| {
12816            this.change_selections(Default::default(), window, cx, |s| {
12817                s.move_with(|map, selection| {
12818                    if selection.is_empty() {
12819                        let cursor = if action.ignore_newlines {
12820                            movement::next_word_end(map, selection.head())
12821                        } else {
12822                            movement::next_word_end_or_newline(map, selection.head())
12823                        };
12824                        selection.set_head(cursor, SelectionGoal::None);
12825                    }
12826                });
12827            });
12828            this.insert("", window, cx);
12829        });
12830    }
12831
12832    pub fn delete_to_next_subword_end(
12833        &mut self,
12834        _: &DeleteToNextSubwordEnd,
12835        window: &mut Window,
12836        cx: &mut Context<Self>,
12837    ) {
12838        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12839        self.transact(window, cx, |this, window, cx| {
12840            this.change_selections(Default::default(), window, cx, |s| {
12841                s.move_with(|map, selection| {
12842                    if selection.is_empty() {
12843                        let cursor = movement::next_subword_end(map, selection.head());
12844                        selection.set_head(cursor, SelectionGoal::None);
12845                    }
12846                });
12847            });
12848            this.insert("", window, cx);
12849        });
12850    }
12851
12852    pub fn move_to_beginning_of_line(
12853        &mut self,
12854        action: &MoveToBeginningOfLine,
12855        window: &mut Window,
12856        cx: &mut Context<Self>,
12857    ) {
12858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12859        self.change_selections(Default::default(), window, cx, |s| {
12860            s.move_cursors_with(|map, head, _| {
12861                (
12862                    movement::indented_line_beginning(
12863                        map,
12864                        head,
12865                        action.stop_at_soft_wraps,
12866                        action.stop_at_indent,
12867                    ),
12868                    SelectionGoal::None,
12869                )
12870            });
12871        })
12872    }
12873
12874    pub fn select_to_beginning_of_line(
12875        &mut self,
12876        action: &SelectToBeginningOfLine,
12877        window: &mut Window,
12878        cx: &mut Context<Self>,
12879    ) {
12880        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12881        self.change_selections(Default::default(), window, cx, |s| {
12882            s.move_heads_with(|map, head, _| {
12883                (
12884                    movement::indented_line_beginning(
12885                        map,
12886                        head,
12887                        action.stop_at_soft_wraps,
12888                        action.stop_at_indent,
12889                    ),
12890                    SelectionGoal::None,
12891                )
12892            });
12893        });
12894    }
12895
12896    pub fn delete_to_beginning_of_line(
12897        &mut self,
12898        action: &DeleteToBeginningOfLine,
12899        window: &mut Window,
12900        cx: &mut Context<Self>,
12901    ) {
12902        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12903        self.transact(window, cx, |this, window, cx| {
12904            this.change_selections(Default::default(), window, cx, |s| {
12905                s.move_with(|_, selection| {
12906                    selection.reversed = true;
12907                });
12908            });
12909
12910            this.select_to_beginning_of_line(
12911                &SelectToBeginningOfLine {
12912                    stop_at_soft_wraps: false,
12913                    stop_at_indent: action.stop_at_indent,
12914                },
12915                window,
12916                cx,
12917            );
12918            this.backspace(&Backspace, window, cx);
12919        });
12920    }
12921
12922    pub fn move_to_end_of_line(
12923        &mut self,
12924        action: &MoveToEndOfLine,
12925        window: &mut Window,
12926        cx: &mut Context<Self>,
12927    ) {
12928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12929        self.change_selections(Default::default(), window, cx, |s| {
12930            s.move_cursors_with(|map, head, _| {
12931                (
12932                    movement::line_end(map, head, action.stop_at_soft_wraps),
12933                    SelectionGoal::None,
12934                )
12935            });
12936        })
12937    }
12938
12939    pub fn select_to_end_of_line(
12940        &mut self,
12941        action: &SelectToEndOfLine,
12942        window: &mut Window,
12943        cx: &mut Context<Self>,
12944    ) {
12945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12946        self.change_selections(Default::default(), window, cx, |s| {
12947            s.move_heads_with(|map, head, _| {
12948                (
12949                    movement::line_end(map, head, action.stop_at_soft_wraps),
12950                    SelectionGoal::None,
12951                )
12952            });
12953        })
12954    }
12955
12956    pub fn delete_to_end_of_line(
12957        &mut self,
12958        _: &DeleteToEndOfLine,
12959        window: &mut Window,
12960        cx: &mut Context<Self>,
12961    ) {
12962        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12963        self.transact(window, cx, |this, window, cx| {
12964            this.select_to_end_of_line(
12965                &SelectToEndOfLine {
12966                    stop_at_soft_wraps: false,
12967                },
12968                window,
12969                cx,
12970            );
12971            this.delete(&Delete, window, cx);
12972        });
12973    }
12974
12975    pub fn cut_to_end_of_line(
12976        &mut self,
12977        _: &CutToEndOfLine,
12978        window: &mut Window,
12979        cx: &mut Context<Self>,
12980    ) {
12981        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12982        self.transact(window, cx, |this, window, cx| {
12983            this.select_to_end_of_line(
12984                &SelectToEndOfLine {
12985                    stop_at_soft_wraps: false,
12986                },
12987                window,
12988                cx,
12989            );
12990            this.cut(&Cut, window, cx);
12991        });
12992    }
12993
12994    pub fn move_to_start_of_paragraph(
12995        &mut self,
12996        _: &MoveToStartOfParagraph,
12997        window: &mut Window,
12998        cx: &mut Context<Self>,
12999    ) {
13000        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13001            cx.propagate();
13002            return;
13003        }
13004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13005        self.change_selections(Default::default(), window, cx, |s| {
13006            s.move_with(|map, selection| {
13007                selection.collapse_to(
13008                    movement::start_of_paragraph(map, selection.head(), 1),
13009                    SelectionGoal::None,
13010                )
13011            });
13012        })
13013    }
13014
13015    pub fn move_to_end_of_paragraph(
13016        &mut self,
13017        _: &MoveToEndOfParagraph,
13018        window: &mut Window,
13019        cx: &mut Context<Self>,
13020    ) {
13021        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13022            cx.propagate();
13023            return;
13024        }
13025        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13026        self.change_selections(Default::default(), window, cx, |s| {
13027            s.move_with(|map, selection| {
13028                selection.collapse_to(
13029                    movement::end_of_paragraph(map, selection.head(), 1),
13030                    SelectionGoal::None,
13031                )
13032            });
13033        })
13034    }
13035
13036    pub fn select_to_start_of_paragraph(
13037        &mut self,
13038        _: &SelectToStartOfParagraph,
13039        window: &mut Window,
13040        cx: &mut Context<Self>,
13041    ) {
13042        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13043            cx.propagate();
13044            return;
13045        }
13046        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13047        self.change_selections(Default::default(), window, cx, |s| {
13048            s.move_heads_with(|map, head, _| {
13049                (
13050                    movement::start_of_paragraph(map, head, 1),
13051                    SelectionGoal::None,
13052                )
13053            });
13054        })
13055    }
13056
13057    pub fn select_to_end_of_paragraph(
13058        &mut self,
13059        _: &SelectToEndOfParagraph,
13060        window: &mut Window,
13061        cx: &mut Context<Self>,
13062    ) {
13063        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13064            cx.propagate();
13065            return;
13066        }
13067        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13068        self.change_selections(Default::default(), window, cx, |s| {
13069            s.move_heads_with(|map, head, _| {
13070                (
13071                    movement::end_of_paragraph(map, head, 1),
13072                    SelectionGoal::None,
13073                )
13074            });
13075        })
13076    }
13077
13078    pub fn move_to_start_of_excerpt(
13079        &mut self,
13080        _: &MoveToStartOfExcerpt,
13081        window: &mut Window,
13082        cx: &mut Context<Self>,
13083    ) {
13084        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13085            cx.propagate();
13086            return;
13087        }
13088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13089        self.change_selections(Default::default(), window, cx, |s| {
13090            s.move_with(|map, selection| {
13091                selection.collapse_to(
13092                    movement::start_of_excerpt(
13093                        map,
13094                        selection.head(),
13095                        workspace::searchable::Direction::Prev,
13096                    ),
13097                    SelectionGoal::None,
13098                )
13099            });
13100        })
13101    }
13102
13103    pub fn move_to_start_of_next_excerpt(
13104        &mut self,
13105        _: &MoveToStartOfNextExcerpt,
13106        window: &mut Window,
13107        cx: &mut Context<Self>,
13108    ) {
13109        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13110            cx.propagate();
13111            return;
13112        }
13113
13114        self.change_selections(Default::default(), window, cx, |s| {
13115            s.move_with(|map, selection| {
13116                selection.collapse_to(
13117                    movement::start_of_excerpt(
13118                        map,
13119                        selection.head(),
13120                        workspace::searchable::Direction::Next,
13121                    ),
13122                    SelectionGoal::None,
13123                )
13124            });
13125        })
13126    }
13127
13128    pub fn move_to_end_of_excerpt(
13129        &mut self,
13130        _: &MoveToEndOfExcerpt,
13131        window: &mut Window,
13132        cx: &mut Context<Self>,
13133    ) {
13134        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13135            cx.propagate();
13136            return;
13137        }
13138        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13139        self.change_selections(Default::default(), window, cx, |s| {
13140            s.move_with(|map, selection| {
13141                selection.collapse_to(
13142                    movement::end_of_excerpt(
13143                        map,
13144                        selection.head(),
13145                        workspace::searchable::Direction::Next,
13146                    ),
13147                    SelectionGoal::None,
13148                )
13149            });
13150        })
13151    }
13152
13153    pub fn move_to_end_of_previous_excerpt(
13154        &mut self,
13155        _: &MoveToEndOfPreviousExcerpt,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13160            cx.propagate();
13161            return;
13162        }
13163        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13164        self.change_selections(Default::default(), window, cx, |s| {
13165            s.move_with(|map, selection| {
13166                selection.collapse_to(
13167                    movement::end_of_excerpt(
13168                        map,
13169                        selection.head(),
13170                        workspace::searchable::Direction::Prev,
13171                    ),
13172                    SelectionGoal::None,
13173                )
13174            });
13175        })
13176    }
13177
13178    pub fn select_to_start_of_excerpt(
13179        &mut self,
13180        _: &SelectToStartOfExcerpt,
13181        window: &mut Window,
13182        cx: &mut Context<Self>,
13183    ) {
13184        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13185            cx.propagate();
13186            return;
13187        }
13188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13189        self.change_selections(Default::default(), window, cx, |s| {
13190            s.move_heads_with(|map, head, _| {
13191                (
13192                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13193                    SelectionGoal::None,
13194                )
13195            });
13196        })
13197    }
13198
13199    pub fn select_to_start_of_next_excerpt(
13200        &mut self,
13201        _: &SelectToStartOfNextExcerpt,
13202        window: &mut Window,
13203        cx: &mut Context<Self>,
13204    ) {
13205        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13206            cx.propagate();
13207            return;
13208        }
13209        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13210        self.change_selections(Default::default(), window, cx, |s| {
13211            s.move_heads_with(|map, head, _| {
13212                (
13213                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13214                    SelectionGoal::None,
13215                )
13216            });
13217        })
13218    }
13219
13220    pub fn select_to_end_of_excerpt(
13221        &mut self,
13222        _: &SelectToEndOfExcerpt,
13223        window: &mut Window,
13224        cx: &mut Context<Self>,
13225    ) {
13226        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13227            cx.propagate();
13228            return;
13229        }
13230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13231        self.change_selections(Default::default(), window, cx, |s| {
13232            s.move_heads_with(|map, head, _| {
13233                (
13234                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13235                    SelectionGoal::None,
13236                )
13237            });
13238        })
13239    }
13240
13241    pub fn select_to_end_of_previous_excerpt(
13242        &mut self,
13243        _: &SelectToEndOfPreviousExcerpt,
13244        window: &mut Window,
13245        cx: &mut Context<Self>,
13246    ) {
13247        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13248            cx.propagate();
13249            return;
13250        }
13251        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13252        self.change_selections(Default::default(), window, cx, |s| {
13253            s.move_heads_with(|map, head, _| {
13254                (
13255                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13256                    SelectionGoal::None,
13257                )
13258            });
13259        })
13260    }
13261
13262    pub fn move_to_beginning(
13263        &mut self,
13264        _: &MoveToBeginning,
13265        window: &mut Window,
13266        cx: &mut Context<Self>,
13267    ) {
13268        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13269            cx.propagate();
13270            return;
13271        }
13272        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13273        self.change_selections(Default::default(), window, cx, |s| {
13274            s.select_ranges(vec![0..0]);
13275        });
13276    }
13277
13278    pub fn select_to_beginning(
13279        &mut self,
13280        _: &SelectToBeginning,
13281        window: &mut Window,
13282        cx: &mut Context<Self>,
13283    ) {
13284        let mut selection = self.selections.last::<Point>(cx);
13285        selection.set_head(Point::zero(), SelectionGoal::None);
13286        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13287        self.change_selections(Default::default(), window, cx, |s| {
13288            s.select(vec![selection]);
13289        });
13290    }
13291
13292    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13293        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13294            cx.propagate();
13295            return;
13296        }
13297        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13298        let cursor = self.buffer.read(cx).read(cx).len();
13299        self.change_selections(Default::default(), window, cx, |s| {
13300            s.select_ranges(vec![cursor..cursor])
13301        });
13302    }
13303
13304    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13305        self.nav_history = nav_history;
13306    }
13307
13308    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13309        self.nav_history.as_ref()
13310    }
13311
13312    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13313        self.push_to_nav_history(
13314            self.selections.newest_anchor().head(),
13315            None,
13316            false,
13317            true,
13318            cx,
13319        );
13320    }
13321
13322    fn push_to_nav_history(
13323        &mut self,
13324        cursor_anchor: Anchor,
13325        new_position: Option<Point>,
13326        is_deactivate: bool,
13327        always: bool,
13328        cx: &mut Context<Self>,
13329    ) {
13330        if let Some(nav_history) = self.nav_history.as_mut() {
13331            let buffer = self.buffer.read(cx).read(cx);
13332            let cursor_position = cursor_anchor.to_point(&buffer);
13333            let scroll_state = self.scroll_manager.anchor();
13334            let scroll_top_row = scroll_state.top_row(&buffer);
13335            drop(buffer);
13336
13337            if let Some(new_position) = new_position {
13338                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13339                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13340                    return;
13341                }
13342            }
13343
13344            nav_history.push(
13345                Some(NavigationData {
13346                    cursor_anchor,
13347                    cursor_position,
13348                    scroll_anchor: scroll_state,
13349                    scroll_top_row,
13350                }),
13351                cx,
13352            );
13353            cx.emit(EditorEvent::PushedToNavHistory {
13354                anchor: cursor_anchor,
13355                is_deactivate,
13356            })
13357        }
13358    }
13359
13360    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13361        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13362        let buffer = self.buffer.read(cx).snapshot(cx);
13363        let mut selection = self.selections.first::<usize>(cx);
13364        selection.set_head(buffer.len(), SelectionGoal::None);
13365        self.change_selections(Default::default(), window, cx, |s| {
13366            s.select(vec![selection]);
13367        });
13368    }
13369
13370    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13371        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13372        let end = self.buffer.read(cx).read(cx).len();
13373        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13374            s.select_ranges(vec![0..end]);
13375        });
13376    }
13377
13378    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13380        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13381        let mut selections = self.selections.all::<Point>(cx);
13382        let max_point = display_map.buffer_snapshot.max_point();
13383        for selection in &mut selections {
13384            let rows = selection.spanned_rows(true, &display_map);
13385            selection.start = Point::new(rows.start.0, 0);
13386            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13387            selection.reversed = false;
13388        }
13389        self.change_selections(Default::default(), window, cx, |s| {
13390            s.select(selections);
13391        });
13392    }
13393
13394    pub fn split_selection_into_lines(
13395        &mut self,
13396        _: &SplitSelectionIntoLines,
13397        window: &mut Window,
13398        cx: &mut Context<Self>,
13399    ) {
13400        let selections = self
13401            .selections
13402            .all::<Point>(cx)
13403            .into_iter()
13404            .map(|selection| selection.start..selection.end)
13405            .collect::<Vec<_>>();
13406        self.unfold_ranges(&selections, true, true, cx);
13407
13408        let mut new_selection_ranges = Vec::new();
13409        {
13410            let buffer = self.buffer.read(cx).read(cx);
13411            for selection in selections {
13412                for row in selection.start.row..selection.end.row {
13413                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13414                    new_selection_ranges.push(cursor..cursor);
13415                }
13416
13417                let is_multiline_selection = selection.start.row != selection.end.row;
13418                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13419                // so this action feels more ergonomic when paired with other selection operations
13420                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13421                if !should_skip_last {
13422                    new_selection_ranges.push(selection.end..selection.end);
13423                }
13424            }
13425        }
13426        self.change_selections(Default::default(), window, cx, |s| {
13427            s.select_ranges(new_selection_ranges);
13428        });
13429    }
13430
13431    pub fn add_selection_above(
13432        &mut self,
13433        _: &AddSelectionAbove,
13434        window: &mut Window,
13435        cx: &mut Context<Self>,
13436    ) {
13437        self.add_selection(true, window, cx);
13438    }
13439
13440    pub fn add_selection_below(
13441        &mut self,
13442        _: &AddSelectionBelow,
13443        window: &mut Window,
13444        cx: &mut Context<Self>,
13445    ) {
13446        self.add_selection(false, window, cx);
13447    }
13448
13449    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13450        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13451
13452        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13453        let all_selections = self.selections.all::<Point>(cx);
13454        let text_layout_details = self.text_layout_details(window);
13455
13456        let (mut columnar_selections, new_selections_to_columnarize) = {
13457            if let Some(state) = self.add_selections_state.as_ref() {
13458                let columnar_selection_ids: HashSet<_> = state
13459                    .groups
13460                    .iter()
13461                    .flat_map(|group| group.stack.iter())
13462                    .copied()
13463                    .collect();
13464
13465                all_selections
13466                    .into_iter()
13467                    .partition(|s| columnar_selection_ids.contains(&s.id))
13468            } else {
13469                (Vec::new(), all_selections)
13470            }
13471        };
13472
13473        let mut state = self
13474            .add_selections_state
13475            .take()
13476            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13477
13478        for selection in new_selections_to_columnarize {
13479            let range = selection.display_range(&display_map).sorted();
13480            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13481            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13482            let positions = start_x.min(end_x)..start_x.max(end_x);
13483            let mut stack = Vec::new();
13484            for row in range.start.row().0..=range.end.row().0 {
13485                if let Some(selection) = self.selections.build_columnar_selection(
13486                    &display_map,
13487                    DisplayRow(row),
13488                    &positions,
13489                    selection.reversed,
13490                    &text_layout_details,
13491                ) {
13492                    stack.push(selection.id);
13493                    columnar_selections.push(selection);
13494                }
13495            }
13496            if !stack.is_empty() {
13497                if above {
13498                    stack.reverse();
13499                }
13500                state.groups.push(AddSelectionsGroup { above, stack });
13501            }
13502        }
13503
13504        let mut final_selections = Vec::new();
13505        let end_row = if above {
13506            DisplayRow(0)
13507        } else {
13508            display_map.max_point().row()
13509        };
13510
13511        let mut last_added_item_per_group = HashMap::default();
13512        for group in state.groups.iter_mut() {
13513            if let Some(last_id) = group.stack.last() {
13514                last_added_item_per_group.insert(*last_id, group);
13515            }
13516        }
13517
13518        for selection in columnar_selections {
13519            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13520                if above == group.above {
13521                    let range = selection.display_range(&display_map).sorted();
13522                    debug_assert_eq!(range.start.row(), range.end.row());
13523                    let mut row = range.start.row();
13524                    let positions =
13525                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13526                            px(start)..px(end)
13527                        } else {
13528                            let start_x =
13529                                display_map.x_for_display_point(range.start, &text_layout_details);
13530                            let end_x =
13531                                display_map.x_for_display_point(range.end, &text_layout_details);
13532                            start_x.min(end_x)..start_x.max(end_x)
13533                        };
13534
13535                    let mut maybe_new_selection = None;
13536                    while row != end_row {
13537                        if above {
13538                            row.0 -= 1;
13539                        } else {
13540                            row.0 += 1;
13541                        }
13542                        if let Some(new_selection) = self.selections.build_columnar_selection(
13543                            &display_map,
13544                            row,
13545                            &positions,
13546                            selection.reversed,
13547                            &text_layout_details,
13548                        ) {
13549                            maybe_new_selection = Some(new_selection);
13550                            break;
13551                        }
13552                    }
13553
13554                    if let Some(new_selection) = maybe_new_selection {
13555                        group.stack.push(new_selection.id);
13556                        if above {
13557                            final_selections.push(new_selection);
13558                            final_selections.push(selection);
13559                        } else {
13560                            final_selections.push(selection);
13561                            final_selections.push(new_selection);
13562                        }
13563                    } else {
13564                        final_selections.push(selection);
13565                    }
13566                } else {
13567                    group.stack.pop();
13568                }
13569            } else {
13570                final_selections.push(selection);
13571            }
13572        }
13573
13574        self.change_selections(Default::default(), window, cx, |s| {
13575            s.select(final_selections);
13576        });
13577
13578        let final_selection_ids: HashSet<_> = self
13579            .selections
13580            .all::<Point>(cx)
13581            .iter()
13582            .map(|s| s.id)
13583            .collect();
13584        state.groups.retain_mut(|group| {
13585            // selections might get merged above so we remove invalid items from stacks
13586            group.stack.retain(|id| final_selection_ids.contains(id));
13587
13588            // single selection in stack can be treated as initial state
13589            group.stack.len() > 1
13590        });
13591
13592        if !state.groups.is_empty() {
13593            self.add_selections_state = Some(state);
13594        }
13595    }
13596
13597    fn select_match_ranges(
13598        &mut self,
13599        range: Range<usize>,
13600        reversed: bool,
13601        replace_newest: bool,
13602        auto_scroll: Option<Autoscroll>,
13603        window: &mut Window,
13604        cx: &mut Context<Editor>,
13605    ) {
13606        self.unfold_ranges(
13607            std::slice::from_ref(&range),
13608            false,
13609            auto_scroll.is_some(),
13610            cx,
13611        );
13612        let effects = if let Some(scroll) = auto_scroll {
13613            SelectionEffects::scroll(scroll)
13614        } else {
13615            SelectionEffects::no_scroll()
13616        };
13617        self.change_selections(effects, window, cx, |s| {
13618            if replace_newest {
13619                s.delete(s.newest_anchor().id);
13620            }
13621            if reversed {
13622                s.insert_range(range.end..range.start);
13623            } else {
13624                s.insert_range(range);
13625            }
13626        });
13627    }
13628
13629    pub fn select_next_match_internal(
13630        &mut self,
13631        display_map: &DisplaySnapshot,
13632        replace_newest: bool,
13633        autoscroll: Option<Autoscroll>,
13634        window: &mut Window,
13635        cx: &mut Context<Self>,
13636    ) -> Result<()> {
13637        let buffer = &display_map.buffer_snapshot;
13638        let mut selections = self.selections.all::<usize>(cx);
13639        if let Some(mut select_next_state) = self.select_next_state.take() {
13640            let query = &select_next_state.query;
13641            if !select_next_state.done {
13642                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13643                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13644                let mut next_selected_range = None;
13645
13646                let bytes_after_last_selection =
13647                    buffer.bytes_in_range(last_selection.end..buffer.len());
13648                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13649                let query_matches = query
13650                    .stream_find_iter(bytes_after_last_selection)
13651                    .map(|result| (last_selection.end, result))
13652                    .chain(
13653                        query
13654                            .stream_find_iter(bytes_before_first_selection)
13655                            .map(|result| (0, result)),
13656                    );
13657
13658                for (start_offset, query_match) in query_matches {
13659                    let query_match = query_match.unwrap(); // can only fail due to I/O
13660                    let offset_range =
13661                        start_offset + query_match.start()..start_offset + query_match.end();
13662
13663                    if !select_next_state.wordwise
13664                        || (!buffer.is_inside_word(offset_range.start, false)
13665                            && !buffer.is_inside_word(offset_range.end, false))
13666                    {
13667                        // TODO: This is n^2, because we might check all the selections
13668                        if !selections
13669                            .iter()
13670                            .any(|selection| selection.range().overlaps(&offset_range))
13671                        {
13672                            next_selected_range = Some(offset_range);
13673                            break;
13674                        }
13675                    }
13676                }
13677
13678                if let Some(next_selected_range) = next_selected_range {
13679                    self.select_match_ranges(
13680                        next_selected_range,
13681                        last_selection.reversed,
13682                        replace_newest,
13683                        autoscroll,
13684                        window,
13685                        cx,
13686                    );
13687                } else {
13688                    select_next_state.done = true;
13689                }
13690            }
13691
13692            self.select_next_state = Some(select_next_state);
13693        } else {
13694            let mut only_carets = true;
13695            let mut same_text_selected = true;
13696            let mut selected_text = None;
13697
13698            let mut selections_iter = selections.iter().peekable();
13699            while let Some(selection) = selections_iter.next() {
13700                if selection.start != selection.end {
13701                    only_carets = false;
13702                }
13703
13704                if same_text_selected {
13705                    if selected_text.is_none() {
13706                        selected_text =
13707                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13708                    }
13709
13710                    if let Some(next_selection) = selections_iter.peek() {
13711                        if next_selection.range().len() == selection.range().len() {
13712                            let next_selected_text = buffer
13713                                .text_for_range(next_selection.range())
13714                                .collect::<String>();
13715                            if Some(next_selected_text) != selected_text {
13716                                same_text_selected = false;
13717                                selected_text = None;
13718                            }
13719                        } else {
13720                            same_text_selected = false;
13721                            selected_text = None;
13722                        }
13723                    }
13724                }
13725            }
13726
13727            if only_carets {
13728                for selection in &mut selections {
13729                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13730                    selection.start = word_range.start;
13731                    selection.end = word_range.end;
13732                    selection.goal = SelectionGoal::None;
13733                    selection.reversed = false;
13734                    self.select_match_ranges(
13735                        selection.start..selection.end,
13736                        selection.reversed,
13737                        replace_newest,
13738                        autoscroll,
13739                        window,
13740                        cx,
13741                    );
13742                }
13743
13744                if selections.len() == 1 {
13745                    let selection = selections
13746                        .last()
13747                        .expect("ensured that there's only one selection");
13748                    let query = buffer
13749                        .text_for_range(selection.start..selection.end)
13750                        .collect::<String>();
13751                    let is_empty = query.is_empty();
13752                    let select_state = SelectNextState {
13753                        query: AhoCorasick::new(&[query])?,
13754                        wordwise: true,
13755                        done: is_empty,
13756                    };
13757                    self.select_next_state = Some(select_state);
13758                } else {
13759                    self.select_next_state = None;
13760                }
13761            } else if let Some(selected_text) = selected_text {
13762                self.select_next_state = Some(SelectNextState {
13763                    query: AhoCorasick::new(&[selected_text])?,
13764                    wordwise: false,
13765                    done: false,
13766                });
13767                self.select_next_match_internal(
13768                    display_map,
13769                    replace_newest,
13770                    autoscroll,
13771                    window,
13772                    cx,
13773                )?;
13774            }
13775        }
13776        Ok(())
13777    }
13778
13779    pub fn select_all_matches(
13780        &mut self,
13781        _action: &SelectAllMatches,
13782        window: &mut Window,
13783        cx: &mut Context<Self>,
13784    ) -> Result<()> {
13785        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13786
13787        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13788
13789        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13790        let Some(select_next_state) = self.select_next_state.as_mut() else {
13791            return Ok(());
13792        };
13793        if select_next_state.done {
13794            return Ok(());
13795        }
13796
13797        let mut new_selections = Vec::new();
13798
13799        let reversed = self.selections.oldest::<usize>(cx).reversed;
13800        let buffer = &display_map.buffer_snapshot;
13801        let query_matches = select_next_state
13802            .query
13803            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13804
13805        for query_match in query_matches.into_iter() {
13806            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13807            let offset_range = if reversed {
13808                query_match.end()..query_match.start()
13809            } else {
13810                query_match.start()..query_match.end()
13811            };
13812
13813            if !select_next_state.wordwise
13814                || (!buffer.is_inside_word(offset_range.start, false)
13815                    && !buffer.is_inside_word(offset_range.end, false))
13816            {
13817                new_selections.push(offset_range.start..offset_range.end);
13818            }
13819        }
13820
13821        select_next_state.done = true;
13822
13823        if new_selections.is_empty() {
13824            log::error!("bug: new_selections is empty in select_all_matches");
13825            return Ok(());
13826        }
13827
13828        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13829        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13830            selections.select_ranges(new_selections)
13831        });
13832
13833        Ok(())
13834    }
13835
13836    pub fn select_next(
13837        &mut self,
13838        action: &SelectNext,
13839        window: &mut Window,
13840        cx: &mut Context<Self>,
13841    ) -> Result<()> {
13842        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13843        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13844        self.select_next_match_internal(
13845            &display_map,
13846            action.replace_newest,
13847            Some(Autoscroll::newest()),
13848            window,
13849            cx,
13850        )?;
13851        Ok(())
13852    }
13853
13854    pub fn select_previous(
13855        &mut self,
13856        action: &SelectPrevious,
13857        window: &mut Window,
13858        cx: &mut Context<Self>,
13859    ) -> Result<()> {
13860        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13861        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13862        let buffer = &display_map.buffer_snapshot;
13863        let mut selections = self.selections.all::<usize>(cx);
13864        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13865            let query = &select_prev_state.query;
13866            if !select_prev_state.done {
13867                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13868                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13869                let mut next_selected_range = None;
13870                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13871                let bytes_before_last_selection =
13872                    buffer.reversed_bytes_in_range(0..last_selection.start);
13873                let bytes_after_first_selection =
13874                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13875                let query_matches = query
13876                    .stream_find_iter(bytes_before_last_selection)
13877                    .map(|result| (last_selection.start, result))
13878                    .chain(
13879                        query
13880                            .stream_find_iter(bytes_after_first_selection)
13881                            .map(|result| (buffer.len(), result)),
13882                    );
13883                for (end_offset, query_match) in query_matches {
13884                    let query_match = query_match.unwrap(); // can only fail due to I/O
13885                    let offset_range =
13886                        end_offset - query_match.end()..end_offset - query_match.start();
13887
13888                    if !select_prev_state.wordwise
13889                        || (!buffer.is_inside_word(offset_range.start, false)
13890                            && !buffer.is_inside_word(offset_range.end, false))
13891                    {
13892                        next_selected_range = Some(offset_range);
13893                        break;
13894                    }
13895                }
13896
13897                if let Some(next_selected_range) = next_selected_range {
13898                    self.select_match_ranges(
13899                        next_selected_range,
13900                        last_selection.reversed,
13901                        action.replace_newest,
13902                        Some(Autoscroll::newest()),
13903                        window,
13904                        cx,
13905                    );
13906                } else {
13907                    select_prev_state.done = true;
13908                }
13909            }
13910
13911            self.select_prev_state = Some(select_prev_state);
13912        } else {
13913            let mut only_carets = true;
13914            let mut same_text_selected = true;
13915            let mut selected_text = None;
13916
13917            let mut selections_iter = selections.iter().peekable();
13918            while let Some(selection) = selections_iter.next() {
13919                if selection.start != selection.end {
13920                    only_carets = false;
13921                }
13922
13923                if same_text_selected {
13924                    if selected_text.is_none() {
13925                        selected_text =
13926                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13927                    }
13928
13929                    if let Some(next_selection) = selections_iter.peek() {
13930                        if next_selection.range().len() == selection.range().len() {
13931                            let next_selected_text = buffer
13932                                .text_for_range(next_selection.range())
13933                                .collect::<String>();
13934                            if Some(next_selected_text) != selected_text {
13935                                same_text_selected = false;
13936                                selected_text = None;
13937                            }
13938                        } else {
13939                            same_text_selected = false;
13940                            selected_text = None;
13941                        }
13942                    }
13943                }
13944            }
13945
13946            if only_carets {
13947                for selection in &mut selections {
13948                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13949                    selection.start = word_range.start;
13950                    selection.end = word_range.end;
13951                    selection.goal = SelectionGoal::None;
13952                    selection.reversed = false;
13953                    self.select_match_ranges(
13954                        selection.start..selection.end,
13955                        selection.reversed,
13956                        action.replace_newest,
13957                        Some(Autoscroll::newest()),
13958                        window,
13959                        cx,
13960                    );
13961                }
13962                if selections.len() == 1 {
13963                    let selection = selections
13964                        .last()
13965                        .expect("ensured that there's only one selection");
13966                    let query = buffer
13967                        .text_for_range(selection.start..selection.end)
13968                        .collect::<String>();
13969                    let is_empty = query.is_empty();
13970                    let select_state = SelectNextState {
13971                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13972                        wordwise: true,
13973                        done: is_empty,
13974                    };
13975                    self.select_prev_state = Some(select_state);
13976                } else {
13977                    self.select_prev_state = None;
13978                }
13979            } else if let Some(selected_text) = selected_text {
13980                self.select_prev_state = Some(SelectNextState {
13981                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13982                    wordwise: false,
13983                    done: false,
13984                });
13985                self.select_previous(action, window, cx)?;
13986            }
13987        }
13988        Ok(())
13989    }
13990
13991    pub fn find_next_match(
13992        &mut self,
13993        _: &FindNextMatch,
13994        window: &mut Window,
13995        cx: &mut Context<Self>,
13996    ) -> Result<()> {
13997        let selections = self.selections.disjoint_anchors();
13998        match selections.first() {
13999            Some(first) if selections.len() >= 2 => {
14000                self.change_selections(Default::default(), window, cx, |s| {
14001                    s.select_ranges([first.range()]);
14002                });
14003            }
14004            _ => self.select_next(
14005                &SelectNext {
14006                    replace_newest: true,
14007                },
14008                window,
14009                cx,
14010            )?,
14011        }
14012        Ok(())
14013    }
14014
14015    pub fn find_previous_match(
14016        &mut self,
14017        _: &FindPreviousMatch,
14018        window: &mut Window,
14019        cx: &mut Context<Self>,
14020    ) -> Result<()> {
14021        let selections = self.selections.disjoint_anchors();
14022        match selections.last() {
14023            Some(last) if selections.len() >= 2 => {
14024                self.change_selections(Default::default(), window, cx, |s| {
14025                    s.select_ranges([last.range()]);
14026                });
14027            }
14028            _ => self.select_previous(
14029                &SelectPrevious {
14030                    replace_newest: true,
14031                },
14032                window,
14033                cx,
14034            )?,
14035        }
14036        Ok(())
14037    }
14038
14039    pub fn toggle_comments(
14040        &mut self,
14041        action: &ToggleComments,
14042        window: &mut Window,
14043        cx: &mut Context<Self>,
14044    ) {
14045        if self.read_only(cx) {
14046            return;
14047        }
14048        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14049        let text_layout_details = &self.text_layout_details(window);
14050        self.transact(window, cx, |this, window, cx| {
14051            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14052            let mut edits = Vec::new();
14053            let mut selection_edit_ranges = Vec::new();
14054            let mut last_toggled_row = None;
14055            let snapshot = this.buffer.read(cx).read(cx);
14056            let empty_str: Arc<str> = Arc::default();
14057            let mut suffixes_inserted = Vec::new();
14058            let ignore_indent = action.ignore_indent;
14059
14060            fn comment_prefix_range(
14061                snapshot: &MultiBufferSnapshot,
14062                row: MultiBufferRow,
14063                comment_prefix: &str,
14064                comment_prefix_whitespace: &str,
14065                ignore_indent: bool,
14066            ) -> Range<Point> {
14067                let indent_size = if ignore_indent {
14068                    0
14069                } else {
14070                    snapshot.indent_size_for_line(row).len
14071                };
14072
14073                let start = Point::new(row.0, indent_size);
14074
14075                let mut line_bytes = snapshot
14076                    .bytes_in_range(start..snapshot.max_point())
14077                    .flatten()
14078                    .copied();
14079
14080                // If this line currently begins with the line comment prefix, then record
14081                // the range containing the prefix.
14082                if line_bytes
14083                    .by_ref()
14084                    .take(comment_prefix.len())
14085                    .eq(comment_prefix.bytes())
14086                {
14087                    // Include any whitespace that matches the comment prefix.
14088                    let matching_whitespace_len = line_bytes
14089                        .zip(comment_prefix_whitespace.bytes())
14090                        .take_while(|(a, b)| a == b)
14091                        .count() as u32;
14092                    let end = Point::new(
14093                        start.row,
14094                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14095                    );
14096                    start..end
14097                } else {
14098                    start..start
14099                }
14100            }
14101
14102            fn comment_suffix_range(
14103                snapshot: &MultiBufferSnapshot,
14104                row: MultiBufferRow,
14105                comment_suffix: &str,
14106                comment_suffix_has_leading_space: bool,
14107            ) -> Range<Point> {
14108                let end = Point::new(row.0, snapshot.line_len(row));
14109                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14110
14111                let mut line_end_bytes = snapshot
14112                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14113                    .flatten()
14114                    .copied();
14115
14116                let leading_space_len = if suffix_start_column > 0
14117                    && line_end_bytes.next() == Some(b' ')
14118                    && comment_suffix_has_leading_space
14119                {
14120                    1
14121                } else {
14122                    0
14123                };
14124
14125                // If this line currently begins with the line comment prefix, then record
14126                // the range containing the prefix.
14127                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14128                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14129                    start..end
14130                } else {
14131                    end..end
14132                }
14133            }
14134
14135            // TODO: Handle selections that cross excerpts
14136            for selection in &mut selections {
14137                let start_column = snapshot
14138                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14139                    .len;
14140                let language = if let Some(language) =
14141                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14142                {
14143                    language
14144                } else {
14145                    continue;
14146                };
14147
14148                selection_edit_ranges.clear();
14149
14150                // If multiple selections contain a given row, avoid processing that
14151                // row more than once.
14152                let mut start_row = MultiBufferRow(selection.start.row);
14153                if last_toggled_row == Some(start_row) {
14154                    start_row = start_row.next_row();
14155                }
14156                let end_row =
14157                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14158                        MultiBufferRow(selection.end.row - 1)
14159                    } else {
14160                        MultiBufferRow(selection.end.row)
14161                    };
14162                last_toggled_row = Some(end_row);
14163
14164                if start_row > end_row {
14165                    continue;
14166                }
14167
14168                // If the language has line comments, toggle those.
14169                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14170
14171                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14172                if ignore_indent {
14173                    full_comment_prefixes = full_comment_prefixes
14174                        .into_iter()
14175                        .map(|s| Arc::from(s.trim_end()))
14176                        .collect();
14177                }
14178
14179                if !full_comment_prefixes.is_empty() {
14180                    let first_prefix = full_comment_prefixes
14181                        .first()
14182                        .expect("prefixes is non-empty");
14183                    let prefix_trimmed_lengths = full_comment_prefixes
14184                        .iter()
14185                        .map(|p| p.trim_end_matches(' ').len())
14186                        .collect::<SmallVec<[usize; 4]>>();
14187
14188                    let mut all_selection_lines_are_comments = true;
14189
14190                    for row in start_row.0..=end_row.0 {
14191                        let row = MultiBufferRow(row);
14192                        if start_row < end_row && snapshot.is_line_blank(row) {
14193                            continue;
14194                        }
14195
14196                        let prefix_range = full_comment_prefixes
14197                            .iter()
14198                            .zip(prefix_trimmed_lengths.iter().copied())
14199                            .map(|(prefix, trimmed_prefix_len)| {
14200                                comment_prefix_range(
14201                                    snapshot.deref(),
14202                                    row,
14203                                    &prefix[..trimmed_prefix_len],
14204                                    &prefix[trimmed_prefix_len..],
14205                                    ignore_indent,
14206                                )
14207                            })
14208                            .max_by_key(|range| range.end.column - range.start.column)
14209                            .expect("prefixes is non-empty");
14210
14211                        if prefix_range.is_empty() {
14212                            all_selection_lines_are_comments = false;
14213                        }
14214
14215                        selection_edit_ranges.push(prefix_range);
14216                    }
14217
14218                    if all_selection_lines_are_comments {
14219                        edits.extend(
14220                            selection_edit_ranges
14221                                .iter()
14222                                .cloned()
14223                                .map(|range| (range, empty_str.clone())),
14224                        );
14225                    } else {
14226                        let min_column = selection_edit_ranges
14227                            .iter()
14228                            .map(|range| range.start.column)
14229                            .min()
14230                            .unwrap_or(0);
14231                        edits.extend(selection_edit_ranges.iter().map(|range| {
14232                            let position = Point::new(range.start.row, min_column);
14233                            (position..position, first_prefix.clone())
14234                        }));
14235                    }
14236                } else if let Some((full_comment_prefix, comment_suffix)) =
14237                    language.block_comment_delimiters()
14238                {
14239                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14240                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14241                    let prefix_range = comment_prefix_range(
14242                        snapshot.deref(),
14243                        start_row,
14244                        comment_prefix,
14245                        comment_prefix_whitespace,
14246                        ignore_indent,
14247                    );
14248                    let suffix_range = comment_suffix_range(
14249                        snapshot.deref(),
14250                        end_row,
14251                        comment_suffix.trim_start_matches(' '),
14252                        comment_suffix.starts_with(' '),
14253                    );
14254
14255                    if prefix_range.is_empty() || suffix_range.is_empty() {
14256                        edits.push((
14257                            prefix_range.start..prefix_range.start,
14258                            full_comment_prefix.clone(),
14259                        ));
14260                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14261                        suffixes_inserted.push((end_row, comment_suffix.len()));
14262                    } else {
14263                        edits.push((prefix_range, empty_str.clone()));
14264                        edits.push((suffix_range, empty_str.clone()));
14265                    }
14266                } else {
14267                    continue;
14268                }
14269            }
14270
14271            drop(snapshot);
14272            this.buffer.update(cx, |buffer, cx| {
14273                buffer.edit(edits, None, cx);
14274            });
14275
14276            // Adjust selections so that they end before any comment suffixes that
14277            // were inserted.
14278            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14279            let mut selections = this.selections.all::<Point>(cx);
14280            let snapshot = this.buffer.read(cx).read(cx);
14281            for selection in &mut selections {
14282                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14283                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14284                        Ordering::Less => {
14285                            suffixes_inserted.next();
14286                            continue;
14287                        }
14288                        Ordering::Greater => break,
14289                        Ordering::Equal => {
14290                            if selection.end.column == snapshot.line_len(row) {
14291                                if selection.is_empty() {
14292                                    selection.start.column -= suffix_len as u32;
14293                                }
14294                                selection.end.column -= suffix_len as u32;
14295                            }
14296                            break;
14297                        }
14298                    }
14299                }
14300            }
14301
14302            drop(snapshot);
14303            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14304
14305            let selections = this.selections.all::<Point>(cx);
14306            let selections_on_single_row = selections.windows(2).all(|selections| {
14307                selections[0].start.row == selections[1].start.row
14308                    && selections[0].end.row == selections[1].end.row
14309                    && selections[0].start.row == selections[0].end.row
14310            });
14311            let selections_selecting = selections
14312                .iter()
14313                .any(|selection| selection.start != selection.end);
14314            let advance_downwards = action.advance_downwards
14315                && selections_on_single_row
14316                && !selections_selecting
14317                && !matches!(this.mode, EditorMode::SingleLine { .. });
14318
14319            if advance_downwards {
14320                let snapshot = this.buffer.read(cx).snapshot(cx);
14321
14322                this.change_selections(Default::default(), window, cx, |s| {
14323                    s.move_cursors_with(|display_snapshot, display_point, _| {
14324                        let mut point = display_point.to_point(display_snapshot);
14325                        point.row += 1;
14326                        point = snapshot.clip_point(point, Bias::Left);
14327                        let display_point = point.to_display_point(display_snapshot);
14328                        let goal = SelectionGoal::HorizontalPosition(
14329                            display_snapshot
14330                                .x_for_display_point(display_point, text_layout_details)
14331                                .into(),
14332                        );
14333                        (display_point, goal)
14334                    })
14335                });
14336            }
14337        });
14338    }
14339
14340    pub fn select_enclosing_symbol(
14341        &mut self,
14342        _: &SelectEnclosingSymbol,
14343        window: &mut Window,
14344        cx: &mut Context<Self>,
14345    ) {
14346        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14347
14348        let buffer = self.buffer.read(cx).snapshot(cx);
14349        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14350
14351        fn update_selection(
14352            selection: &Selection<usize>,
14353            buffer_snap: &MultiBufferSnapshot,
14354        ) -> Option<Selection<usize>> {
14355            let cursor = selection.head();
14356            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14357            for symbol in symbols.iter().rev() {
14358                let start = symbol.range.start.to_offset(buffer_snap);
14359                let end = symbol.range.end.to_offset(buffer_snap);
14360                let new_range = start..end;
14361                if start < selection.start || end > selection.end {
14362                    return Some(Selection {
14363                        id: selection.id,
14364                        start: new_range.start,
14365                        end: new_range.end,
14366                        goal: SelectionGoal::None,
14367                        reversed: selection.reversed,
14368                    });
14369                }
14370            }
14371            None
14372        }
14373
14374        let mut selected_larger_symbol = false;
14375        let new_selections = old_selections
14376            .iter()
14377            .map(|selection| match update_selection(selection, &buffer) {
14378                Some(new_selection) => {
14379                    if new_selection.range() != selection.range() {
14380                        selected_larger_symbol = true;
14381                    }
14382                    new_selection
14383                }
14384                None => selection.clone(),
14385            })
14386            .collect::<Vec<_>>();
14387
14388        if selected_larger_symbol {
14389            self.change_selections(Default::default(), window, cx, |s| {
14390                s.select(new_selections);
14391            });
14392        }
14393    }
14394
14395    pub fn select_larger_syntax_node(
14396        &mut self,
14397        _: &SelectLargerSyntaxNode,
14398        window: &mut Window,
14399        cx: &mut Context<Self>,
14400    ) {
14401        let Some(visible_row_count) = self.visible_row_count() else {
14402            return;
14403        };
14404        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14405        if old_selections.is_empty() {
14406            return;
14407        }
14408
14409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14410
14411        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14412        let buffer = self.buffer.read(cx).snapshot(cx);
14413
14414        let mut selected_larger_node = false;
14415        let mut new_selections = old_selections
14416            .iter()
14417            .map(|selection| {
14418                let old_range = selection.start..selection.end;
14419
14420                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14421                    // manually select word at selection
14422                    if ["string_content", "inline"].contains(&node.kind()) {
14423                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14424                        // ignore if word is already selected
14425                        if !word_range.is_empty() && old_range != word_range {
14426                            let (last_word_range, _) =
14427                                buffer.surrounding_word(old_range.end, false);
14428                            // only select word if start and end point belongs to same word
14429                            if word_range == last_word_range {
14430                                selected_larger_node = true;
14431                                return Selection {
14432                                    id: selection.id,
14433                                    start: word_range.start,
14434                                    end: word_range.end,
14435                                    goal: SelectionGoal::None,
14436                                    reversed: selection.reversed,
14437                                };
14438                            }
14439                        }
14440                    }
14441                }
14442
14443                let mut new_range = old_range.clone();
14444                while let Some((_node, containing_range)) =
14445                    buffer.syntax_ancestor(new_range.clone())
14446                {
14447                    new_range = match containing_range {
14448                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14449                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14450                    };
14451                    if !display_map.intersects_fold(new_range.start)
14452                        && !display_map.intersects_fold(new_range.end)
14453                    {
14454                        break;
14455                    }
14456                }
14457
14458                selected_larger_node |= new_range != old_range;
14459                Selection {
14460                    id: selection.id,
14461                    start: new_range.start,
14462                    end: new_range.end,
14463                    goal: SelectionGoal::None,
14464                    reversed: selection.reversed,
14465                }
14466            })
14467            .collect::<Vec<_>>();
14468
14469        if !selected_larger_node {
14470            return; // don't put this call in the history
14471        }
14472
14473        // scroll based on transformation done to the last selection created by the user
14474        let (last_old, last_new) = old_selections
14475            .last()
14476            .zip(new_selections.last().cloned())
14477            .expect("old_selections isn't empty");
14478
14479        // revert selection
14480        let is_selection_reversed = {
14481            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14482            new_selections.last_mut().expect("checked above").reversed =
14483                should_newest_selection_be_reversed;
14484            should_newest_selection_be_reversed
14485        };
14486
14487        if selected_larger_node {
14488            self.select_syntax_node_history.disable_clearing = true;
14489            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14490                s.select(new_selections.clone());
14491            });
14492            self.select_syntax_node_history.disable_clearing = false;
14493        }
14494
14495        let start_row = last_new.start.to_display_point(&display_map).row().0;
14496        let end_row = last_new.end.to_display_point(&display_map).row().0;
14497        let selection_height = end_row - start_row + 1;
14498        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14499
14500        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14501        let scroll_behavior = if fits_on_the_screen {
14502            self.request_autoscroll(Autoscroll::fit(), cx);
14503            SelectSyntaxNodeScrollBehavior::FitSelection
14504        } else if is_selection_reversed {
14505            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14506            SelectSyntaxNodeScrollBehavior::CursorTop
14507        } else {
14508            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14509            SelectSyntaxNodeScrollBehavior::CursorBottom
14510        };
14511
14512        self.select_syntax_node_history.push((
14513            old_selections,
14514            scroll_behavior,
14515            is_selection_reversed,
14516        ));
14517    }
14518
14519    pub fn select_smaller_syntax_node(
14520        &mut self,
14521        _: &SelectSmallerSyntaxNode,
14522        window: &mut Window,
14523        cx: &mut Context<Self>,
14524    ) {
14525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14526
14527        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14528            self.select_syntax_node_history.pop()
14529        {
14530            if let Some(selection) = selections.last_mut() {
14531                selection.reversed = is_selection_reversed;
14532            }
14533
14534            self.select_syntax_node_history.disable_clearing = true;
14535            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14536                s.select(selections.to_vec());
14537            });
14538            self.select_syntax_node_history.disable_clearing = false;
14539
14540            match scroll_behavior {
14541                SelectSyntaxNodeScrollBehavior::CursorTop => {
14542                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14543                }
14544                SelectSyntaxNodeScrollBehavior::FitSelection => {
14545                    self.request_autoscroll(Autoscroll::fit(), cx);
14546                }
14547                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14548                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14549                }
14550            }
14551        }
14552    }
14553
14554    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14555        if !EditorSettings::get_global(cx).gutter.runnables {
14556            self.clear_tasks();
14557            return Task::ready(());
14558        }
14559        let project = self.project.as_ref().map(Entity::downgrade);
14560        let task_sources = self.lsp_task_sources(cx);
14561        let multi_buffer = self.buffer.downgrade();
14562        cx.spawn_in(window, async move |editor, cx| {
14563            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14564            let Some(project) = project.and_then(|p| p.upgrade()) else {
14565                return;
14566            };
14567            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14568                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14569            }) else {
14570                return;
14571            };
14572
14573            let hide_runnables = project
14574                .update(cx, |project, cx| {
14575                    // Do not display any test indicators in non-dev server remote projects.
14576                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14577                })
14578                .unwrap_or(true);
14579            if hide_runnables {
14580                return;
14581            }
14582            let new_rows =
14583                cx.background_spawn({
14584                    let snapshot = display_snapshot.clone();
14585                    async move {
14586                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14587                    }
14588                })
14589                    .await;
14590            let Ok(lsp_tasks) =
14591                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14592            else {
14593                return;
14594            };
14595            let lsp_tasks = lsp_tasks.await;
14596
14597            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14598                lsp_tasks
14599                    .into_iter()
14600                    .flat_map(|(kind, tasks)| {
14601                        tasks.into_iter().filter_map(move |(location, task)| {
14602                            Some((kind.clone(), location?, task))
14603                        })
14604                    })
14605                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14606                        let buffer = location.target.buffer;
14607                        let buffer_snapshot = buffer.read(cx).snapshot();
14608                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14609                            |(excerpt_id, snapshot, _)| {
14610                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14611                                    display_snapshot
14612                                        .buffer_snapshot
14613                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14614                                } else {
14615                                    None
14616                                }
14617                            },
14618                        );
14619                        if let Some(offset) = offset {
14620                            let task_buffer_range =
14621                                location.target.range.to_point(&buffer_snapshot);
14622                            let context_buffer_range =
14623                                task_buffer_range.to_offset(&buffer_snapshot);
14624                            let context_range = BufferOffset(context_buffer_range.start)
14625                                ..BufferOffset(context_buffer_range.end);
14626
14627                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14628                                .or_insert_with(|| RunnableTasks {
14629                                    templates: Vec::new(),
14630                                    offset,
14631                                    column: task_buffer_range.start.column,
14632                                    extra_variables: HashMap::default(),
14633                                    context_range,
14634                                })
14635                                .templates
14636                                .push((kind, task.original_task().clone()));
14637                        }
14638
14639                        acc
14640                    })
14641            }) else {
14642                return;
14643            };
14644
14645            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14646                buffer.language_settings(cx).tasks.prefer_lsp
14647            }) else {
14648                return;
14649            };
14650
14651            let rows = Self::runnable_rows(
14652                project,
14653                display_snapshot,
14654                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14655                new_rows,
14656                cx.clone(),
14657            )
14658            .await;
14659            editor
14660                .update(cx, |editor, _| {
14661                    editor.clear_tasks();
14662                    for (key, mut value) in rows {
14663                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14664                            value.templates.extend(lsp_tasks.templates);
14665                        }
14666
14667                        editor.insert_tasks(key, value);
14668                    }
14669                    for (key, value) in lsp_tasks_by_rows {
14670                        editor.insert_tasks(key, value);
14671                    }
14672                })
14673                .ok();
14674        })
14675    }
14676    fn fetch_runnable_ranges(
14677        snapshot: &DisplaySnapshot,
14678        range: Range<Anchor>,
14679    ) -> Vec<language::RunnableRange> {
14680        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14681    }
14682
14683    fn runnable_rows(
14684        project: Entity<Project>,
14685        snapshot: DisplaySnapshot,
14686        prefer_lsp: bool,
14687        runnable_ranges: Vec<RunnableRange>,
14688        cx: AsyncWindowContext,
14689    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14690        cx.spawn(async move |cx| {
14691            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14692            for mut runnable in runnable_ranges {
14693                let Some(tasks) = cx
14694                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14695                    .ok()
14696                else {
14697                    continue;
14698                };
14699                let mut tasks = tasks.await;
14700
14701                if prefer_lsp {
14702                    tasks.retain(|(task_kind, _)| {
14703                        !matches!(task_kind, TaskSourceKind::Language { .. })
14704                    });
14705                }
14706                if tasks.is_empty() {
14707                    continue;
14708                }
14709
14710                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14711                let Some(row) = snapshot
14712                    .buffer_snapshot
14713                    .buffer_line_for_row(MultiBufferRow(point.row))
14714                    .map(|(_, range)| range.start.row)
14715                else {
14716                    continue;
14717                };
14718
14719                let context_range =
14720                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14721                runnable_rows.push((
14722                    (runnable.buffer_id, row),
14723                    RunnableTasks {
14724                        templates: tasks,
14725                        offset: snapshot
14726                            .buffer_snapshot
14727                            .anchor_before(runnable.run_range.start),
14728                        context_range,
14729                        column: point.column,
14730                        extra_variables: runnable.extra_captures,
14731                    },
14732                ));
14733            }
14734            runnable_rows
14735        })
14736    }
14737
14738    fn templates_with_tags(
14739        project: &Entity<Project>,
14740        runnable: &mut Runnable,
14741        cx: &mut App,
14742    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14743        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14744            let (worktree_id, file) = project
14745                .buffer_for_id(runnable.buffer, cx)
14746                .and_then(|buffer| buffer.read(cx).file())
14747                .map(|file| (file.worktree_id(cx), file.clone()))
14748                .unzip();
14749
14750            (
14751                project.task_store().read(cx).task_inventory().cloned(),
14752                worktree_id,
14753                file,
14754            )
14755        });
14756
14757        let tags = mem::take(&mut runnable.tags);
14758        let language = runnable.language.clone();
14759        cx.spawn(async move |cx| {
14760            let mut templates_with_tags = Vec::new();
14761            if let Some(inventory) = inventory {
14762                for RunnableTag(tag) in tags {
14763                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14764                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14765                    }) else {
14766                        return templates_with_tags;
14767                    };
14768                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14769                        move |(_, template)| {
14770                            template.tags.iter().any(|source_tag| source_tag == &tag)
14771                        },
14772                    ));
14773                }
14774            }
14775            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14776
14777            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14778                // Strongest source wins; if we have worktree tag binding, prefer that to
14779                // global and language bindings;
14780                // if we have a global binding, prefer that to language binding.
14781                let first_mismatch = templates_with_tags
14782                    .iter()
14783                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14784                if let Some(index) = first_mismatch {
14785                    templates_with_tags.truncate(index);
14786                }
14787            }
14788
14789            templates_with_tags
14790        })
14791    }
14792
14793    pub fn move_to_enclosing_bracket(
14794        &mut self,
14795        _: &MoveToEnclosingBracket,
14796        window: &mut Window,
14797        cx: &mut Context<Self>,
14798    ) {
14799        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14800        self.change_selections(Default::default(), window, cx, |s| {
14801            s.move_offsets_with(|snapshot, selection| {
14802                let Some(enclosing_bracket_ranges) =
14803                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14804                else {
14805                    return;
14806                };
14807
14808                let mut best_length = usize::MAX;
14809                let mut best_inside = false;
14810                let mut best_in_bracket_range = false;
14811                let mut best_destination = None;
14812                for (open, close) in enclosing_bracket_ranges {
14813                    let close = close.to_inclusive();
14814                    let length = close.end() - open.start;
14815                    let inside = selection.start >= open.end && selection.end <= *close.start();
14816                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14817                        || close.contains(&selection.head());
14818
14819                    // If best is next to a bracket and current isn't, skip
14820                    if !in_bracket_range && best_in_bracket_range {
14821                        continue;
14822                    }
14823
14824                    // Prefer smaller lengths unless best is inside and current isn't
14825                    if length > best_length && (best_inside || !inside) {
14826                        continue;
14827                    }
14828
14829                    best_length = length;
14830                    best_inside = inside;
14831                    best_in_bracket_range = in_bracket_range;
14832                    best_destination = Some(
14833                        if close.contains(&selection.start) && close.contains(&selection.end) {
14834                            if inside { open.end } else { open.start }
14835                        } else if inside {
14836                            *close.start()
14837                        } else {
14838                            *close.end()
14839                        },
14840                    );
14841                }
14842
14843                if let Some(destination) = best_destination {
14844                    selection.collapse_to(destination, SelectionGoal::None);
14845                }
14846            })
14847        });
14848    }
14849
14850    pub fn undo_selection(
14851        &mut self,
14852        _: &UndoSelection,
14853        window: &mut Window,
14854        cx: &mut Context<Self>,
14855    ) {
14856        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14857        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14858            self.selection_history.mode = SelectionHistoryMode::Undoing;
14859            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14860                this.end_selection(window, cx);
14861                this.change_selections(
14862                    SelectionEffects::scroll(Autoscroll::newest()),
14863                    window,
14864                    cx,
14865                    |s| s.select_anchors(entry.selections.to_vec()),
14866                );
14867            });
14868            self.selection_history.mode = SelectionHistoryMode::Normal;
14869
14870            self.select_next_state = entry.select_next_state;
14871            self.select_prev_state = entry.select_prev_state;
14872            self.add_selections_state = entry.add_selections_state;
14873        }
14874    }
14875
14876    pub fn redo_selection(
14877        &mut self,
14878        _: &RedoSelection,
14879        window: &mut Window,
14880        cx: &mut Context<Self>,
14881    ) {
14882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14883        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14884            self.selection_history.mode = SelectionHistoryMode::Redoing;
14885            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14886                this.end_selection(window, cx);
14887                this.change_selections(
14888                    SelectionEffects::scroll(Autoscroll::newest()),
14889                    window,
14890                    cx,
14891                    |s| s.select_anchors(entry.selections.to_vec()),
14892                );
14893            });
14894            self.selection_history.mode = SelectionHistoryMode::Normal;
14895
14896            self.select_next_state = entry.select_next_state;
14897            self.select_prev_state = entry.select_prev_state;
14898            self.add_selections_state = entry.add_selections_state;
14899        }
14900    }
14901
14902    pub fn expand_excerpts(
14903        &mut self,
14904        action: &ExpandExcerpts,
14905        _: &mut Window,
14906        cx: &mut Context<Self>,
14907    ) {
14908        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14909    }
14910
14911    pub fn expand_excerpts_down(
14912        &mut self,
14913        action: &ExpandExcerptsDown,
14914        _: &mut Window,
14915        cx: &mut Context<Self>,
14916    ) {
14917        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14918    }
14919
14920    pub fn expand_excerpts_up(
14921        &mut self,
14922        action: &ExpandExcerptsUp,
14923        _: &mut Window,
14924        cx: &mut Context<Self>,
14925    ) {
14926        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14927    }
14928
14929    pub fn expand_excerpts_for_direction(
14930        &mut self,
14931        lines: u32,
14932        direction: ExpandExcerptDirection,
14933
14934        cx: &mut Context<Self>,
14935    ) {
14936        let selections = self.selections.disjoint_anchors();
14937
14938        let lines = if lines == 0 {
14939            EditorSettings::get_global(cx).expand_excerpt_lines
14940        } else {
14941            lines
14942        };
14943
14944        self.buffer.update(cx, |buffer, cx| {
14945            let snapshot = buffer.snapshot(cx);
14946            let mut excerpt_ids = selections
14947                .iter()
14948                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14949                .collect::<Vec<_>>();
14950            excerpt_ids.sort();
14951            excerpt_ids.dedup();
14952            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14953        })
14954    }
14955
14956    pub fn expand_excerpt(
14957        &mut self,
14958        excerpt: ExcerptId,
14959        direction: ExpandExcerptDirection,
14960        window: &mut Window,
14961        cx: &mut Context<Self>,
14962    ) {
14963        let current_scroll_position = self.scroll_position(cx);
14964        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14965        let mut should_scroll_up = false;
14966
14967        if direction == ExpandExcerptDirection::Down {
14968            let multi_buffer = self.buffer.read(cx);
14969            let snapshot = multi_buffer.snapshot(cx);
14970            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14971                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14972                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14973                        let buffer_snapshot = buffer.read(cx).snapshot();
14974                        let excerpt_end_row =
14975                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14976                        let last_row = buffer_snapshot.max_point().row;
14977                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14978                        should_scroll_up = lines_below >= lines_to_expand;
14979                    }
14980                }
14981            }
14982        }
14983
14984        self.buffer.update(cx, |buffer, cx| {
14985            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14986        });
14987
14988        if should_scroll_up {
14989            let new_scroll_position =
14990                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14991            self.set_scroll_position(new_scroll_position, window, cx);
14992        }
14993    }
14994
14995    pub fn go_to_singleton_buffer_point(
14996        &mut self,
14997        point: Point,
14998        window: &mut Window,
14999        cx: &mut Context<Self>,
15000    ) {
15001        self.go_to_singleton_buffer_range(point..point, window, cx);
15002    }
15003
15004    pub fn go_to_singleton_buffer_range(
15005        &mut self,
15006        range: Range<Point>,
15007        window: &mut Window,
15008        cx: &mut Context<Self>,
15009    ) {
15010        let multibuffer = self.buffer().read(cx);
15011        let Some(buffer) = multibuffer.as_singleton() else {
15012            return;
15013        };
15014        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15015            return;
15016        };
15017        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15018            return;
15019        };
15020        self.change_selections(
15021            SelectionEffects::default().nav_history(true),
15022            window,
15023            cx,
15024            |s| s.select_anchor_ranges([start..end]),
15025        );
15026    }
15027
15028    pub fn go_to_diagnostic(
15029        &mut self,
15030        _: &GoToDiagnostic,
15031        window: &mut Window,
15032        cx: &mut Context<Self>,
15033    ) {
15034        if !self.diagnostics_enabled() {
15035            return;
15036        }
15037        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15038        self.go_to_diagnostic_impl(Direction::Next, window, cx)
15039    }
15040
15041    pub fn go_to_prev_diagnostic(
15042        &mut self,
15043        _: &GoToPreviousDiagnostic,
15044        window: &mut Window,
15045        cx: &mut Context<Self>,
15046    ) {
15047        if !self.diagnostics_enabled() {
15048            return;
15049        }
15050        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15051        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
15052    }
15053
15054    pub fn go_to_diagnostic_impl(
15055        &mut self,
15056        direction: Direction,
15057        window: &mut Window,
15058        cx: &mut Context<Self>,
15059    ) {
15060        let buffer = self.buffer.read(cx).snapshot(cx);
15061        let selection = self.selections.newest::<usize>(cx);
15062
15063        let mut active_group_id = None;
15064        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15065            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15066                active_group_id = Some(active_group.group_id);
15067            }
15068        }
15069
15070        fn filtered(
15071            snapshot: EditorSnapshot,
15072            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15073        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15074            diagnostics
15075                .filter(|entry| entry.range.start != entry.range.end)
15076                .filter(|entry| !entry.diagnostic.is_unnecessary)
15077                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15078        }
15079
15080        let snapshot = self.snapshot(window, cx);
15081        let before = filtered(
15082            snapshot.clone(),
15083            buffer
15084                .diagnostics_in_range(0..selection.start)
15085                .filter(|entry| entry.range.start <= selection.start),
15086        );
15087        let after = filtered(
15088            snapshot,
15089            buffer
15090                .diagnostics_in_range(selection.start..buffer.len())
15091                .filter(|entry| entry.range.start >= selection.start),
15092        );
15093
15094        let mut found: Option<DiagnosticEntry<usize>> = None;
15095        if direction == Direction::Prev {
15096            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15097            {
15098                for diagnostic in prev_diagnostics.into_iter().rev() {
15099                    if diagnostic.range.start != selection.start
15100                        || active_group_id
15101                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15102                    {
15103                        found = Some(diagnostic);
15104                        break 'outer;
15105                    }
15106                }
15107            }
15108        } else {
15109            for diagnostic in after.chain(before) {
15110                if diagnostic.range.start != selection.start
15111                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15112                {
15113                    found = Some(diagnostic);
15114                    break;
15115                }
15116            }
15117        }
15118        let Some(next_diagnostic) = found else {
15119            return;
15120        };
15121
15122        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15123            return;
15124        };
15125        self.change_selections(Default::default(), window, cx, |s| {
15126            s.select_ranges(vec![
15127                next_diagnostic.range.start..next_diagnostic.range.start,
15128            ])
15129        });
15130        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15131        self.refresh_inline_completion(false, true, window, cx);
15132    }
15133
15134    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15135        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15136        let snapshot = self.snapshot(window, cx);
15137        let selection = self.selections.newest::<Point>(cx);
15138        self.go_to_hunk_before_or_after_position(
15139            &snapshot,
15140            selection.head(),
15141            Direction::Next,
15142            window,
15143            cx,
15144        );
15145    }
15146
15147    pub fn go_to_hunk_before_or_after_position(
15148        &mut self,
15149        snapshot: &EditorSnapshot,
15150        position: Point,
15151        direction: Direction,
15152        window: &mut Window,
15153        cx: &mut Context<Editor>,
15154    ) {
15155        let row = if direction == Direction::Next {
15156            self.hunk_after_position(snapshot, position)
15157                .map(|hunk| hunk.row_range.start)
15158        } else {
15159            self.hunk_before_position(snapshot, position)
15160        };
15161
15162        if let Some(row) = row {
15163            let destination = Point::new(row.0, 0);
15164            let autoscroll = Autoscroll::center();
15165
15166            self.unfold_ranges(&[destination..destination], false, false, cx);
15167            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15168                s.select_ranges([destination..destination]);
15169            });
15170        }
15171    }
15172
15173    fn hunk_after_position(
15174        &mut self,
15175        snapshot: &EditorSnapshot,
15176        position: Point,
15177    ) -> Option<MultiBufferDiffHunk> {
15178        snapshot
15179            .buffer_snapshot
15180            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15181            .find(|hunk| hunk.row_range.start.0 > position.row)
15182            .or_else(|| {
15183                snapshot
15184                    .buffer_snapshot
15185                    .diff_hunks_in_range(Point::zero()..position)
15186                    .find(|hunk| hunk.row_range.end.0 < position.row)
15187            })
15188    }
15189
15190    fn go_to_prev_hunk(
15191        &mut self,
15192        _: &GoToPreviousHunk,
15193        window: &mut Window,
15194        cx: &mut Context<Self>,
15195    ) {
15196        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15197        let snapshot = self.snapshot(window, cx);
15198        let selection = self.selections.newest::<Point>(cx);
15199        self.go_to_hunk_before_or_after_position(
15200            &snapshot,
15201            selection.head(),
15202            Direction::Prev,
15203            window,
15204            cx,
15205        );
15206    }
15207
15208    fn hunk_before_position(
15209        &mut self,
15210        snapshot: &EditorSnapshot,
15211        position: Point,
15212    ) -> Option<MultiBufferRow> {
15213        snapshot
15214            .buffer_snapshot
15215            .diff_hunk_before(position)
15216            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15217    }
15218
15219    fn go_to_next_change(
15220        &mut self,
15221        _: &GoToNextChange,
15222        window: &mut Window,
15223        cx: &mut Context<Self>,
15224    ) {
15225        if let Some(selections) = self
15226            .change_list
15227            .next_change(1, Direction::Next)
15228            .map(|s| s.to_vec())
15229        {
15230            self.change_selections(Default::default(), window, cx, |s| {
15231                let map = s.display_map();
15232                s.select_display_ranges(selections.iter().map(|a| {
15233                    let point = a.to_display_point(&map);
15234                    point..point
15235                }))
15236            })
15237        }
15238    }
15239
15240    fn go_to_previous_change(
15241        &mut self,
15242        _: &GoToPreviousChange,
15243        window: &mut Window,
15244        cx: &mut Context<Self>,
15245    ) {
15246        if let Some(selections) = self
15247            .change_list
15248            .next_change(1, Direction::Prev)
15249            .map(|s| s.to_vec())
15250        {
15251            self.change_selections(Default::default(), window, cx, |s| {
15252                let map = s.display_map();
15253                s.select_display_ranges(selections.iter().map(|a| {
15254                    let point = a.to_display_point(&map);
15255                    point..point
15256                }))
15257            })
15258        }
15259    }
15260
15261    fn go_to_line<T: 'static>(
15262        &mut self,
15263        position: Anchor,
15264        highlight_color: Option<Hsla>,
15265        window: &mut Window,
15266        cx: &mut Context<Self>,
15267    ) {
15268        let snapshot = self.snapshot(window, cx).display_snapshot;
15269        let position = position.to_point(&snapshot.buffer_snapshot);
15270        let start = snapshot
15271            .buffer_snapshot
15272            .clip_point(Point::new(position.row, 0), Bias::Left);
15273        let end = start + Point::new(1, 0);
15274        let start = snapshot.buffer_snapshot.anchor_before(start);
15275        let end = snapshot.buffer_snapshot.anchor_before(end);
15276
15277        self.highlight_rows::<T>(
15278            start..end,
15279            highlight_color
15280                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15281            Default::default(),
15282            cx,
15283        );
15284
15285        if self.buffer.read(cx).is_singleton() {
15286            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15287        }
15288    }
15289
15290    pub fn go_to_definition(
15291        &mut self,
15292        _: &GoToDefinition,
15293        window: &mut Window,
15294        cx: &mut Context<Self>,
15295    ) -> Task<Result<Navigated>> {
15296        let definition =
15297            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15298        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15299        cx.spawn_in(window, async move |editor, cx| {
15300            if definition.await? == Navigated::Yes {
15301                return Ok(Navigated::Yes);
15302            }
15303            match fallback_strategy {
15304                GoToDefinitionFallback::None => Ok(Navigated::No),
15305                GoToDefinitionFallback::FindAllReferences => {
15306                    match editor.update_in(cx, |editor, window, cx| {
15307                        editor.find_all_references(&FindAllReferences, window, cx)
15308                    })? {
15309                        Some(references) => references.await,
15310                        None => Ok(Navigated::No),
15311                    }
15312                }
15313            }
15314        })
15315    }
15316
15317    pub fn go_to_declaration(
15318        &mut self,
15319        _: &GoToDeclaration,
15320        window: &mut Window,
15321        cx: &mut Context<Self>,
15322    ) -> Task<Result<Navigated>> {
15323        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15324    }
15325
15326    pub fn go_to_declaration_split(
15327        &mut self,
15328        _: &GoToDeclaration,
15329        window: &mut Window,
15330        cx: &mut Context<Self>,
15331    ) -> Task<Result<Navigated>> {
15332        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15333    }
15334
15335    pub fn go_to_implementation(
15336        &mut self,
15337        _: &GoToImplementation,
15338        window: &mut Window,
15339        cx: &mut Context<Self>,
15340    ) -> Task<Result<Navigated>> {
15341        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15342    }
15343
15344    pub fn go_to_implementation_split(
15345        &mut self,
15346        _: &GoToImplementationSplit,
15347        window: &mut Window,
15348        cx: &mut Context<Self>,
15349    ) -> Task<Result<Navigated>> {
15350        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15351    }
15352
15353    pub fn go_to_type_definition(
15354        &mut self,
15355        _: &GoToTypeDefinition,
15356        window: &mut Window,
15357        cx: &mut Context<Self>,
15358    ) -> Task<Result<Navigated>> {
15359        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15360    }
15361
15362    pub fn go_to_definition_split(
15363        &mut self,
15364        _: &GoToDefinitionSplit,
15365        window: &mut Window,
15366        cx: &mut Context<Self>,
15367    ) -> Task<Result<Navigated>> {
15368        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15369    }
15370
15371    pub fn go_to_type_definition_split(
15372        &mut self,
15373        _: &GoToTypeDefinitionSplit,
15374        window: &mut Window,
15375        cx: &mut Context<Self>,
15376    ) -> Task<Result<Navigated>> {
15377        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15378    }
15379
15380    fn go_to_definition_of_kind(
15381        &mut self,
15382        kind: GotoDefinitionKind,
15383        split: bool,
15384        window: &mut Window,
15385        cx: &mut Context<Self>,
15386    ) -> Task<Result<Navigated>> {
15387        let Some(provider) = self.semantics_provider.clone() else {
15388            return Task::ready(Ok(Navigated::No));
15389        };
15390        let head = self.selections.newest::<usize>(cx).head();
15391        let buffer = self.buffer.read(cx);
15392        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15393            text_anchor
15394        } else {
15395            return Task::ready(Ok(Navigated::No));
15396        };
15397
15398        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15399            return Task::ready(Ok(Navigated::No));
15400        };
15401
15402        cx.spawn_in(window, async move |editor, cx| {
15403            let definitions = definitions.await?;
15404            let navigated = editor
15405                .update_in(cx, |editor, window, cx| {
15406                    editor.navigate_to_hover_links(
15407                        Some(kind),
15408                        definitions
15409                            .into_iter()
15410                            .filter(|location| {
15411                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15412                            })
15413                            .map(HoverLink::Text)
15414                            .collect::<Vec<_>>(),
15415                        split,
15416                        window,
15417                        cx,
15418                    )
15419                })?
15420                .await?;
15421            anyhow::Ok(navigated)
15422        })
15423    }
15424
15425    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15426        let selection = self.selections.newest_anchor();
15427        let head = selection.head();
15428        let tail = selection.tail();
15429
15430        let Some((buffer, start_position)) =
15431            self.buffer.read(cx).text_anchor_for_position(head, cx)
15432        else {
15433            return;
15434        };
15435
15436        let end_position = if head != tail {
15437            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15438                return;
15439            };
15440            Some(pos)
15441        } else {
15442            None
15443        };
15444
15445        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15446            let url = if let Some(end_pos) = end_position {
15447                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15448            } else {
15449                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15450            };
15451
15452            if let Some(url) = url {
15453                editor.update(cx, |_, cx| {
15454                    cx.open_url(&url);
15455                })
15456            } else {
15457                Ok(())
15458            }
15459        });
15460
15461        url_finder.detach();
15462    }
15463
15464    pub fn open_selected_filename(
15465        &mut self,
15466        _: &OpenSelectedFilename,
15467        window: &mut Window,
15468        cx: &mut Context<Self>,
15469    ) {
15470        let Some(workspace) = self.workspace() else {
15471            return;
15472        };
15473
15474        let position = self.selections.newest_anchor().head();
15475
15476        let Some((buffer, buffer_position)) =
15477            self.buffer.read(cx).text_anchor_for_position(position, cx)
15478        else {
15479            return;
15480        };
15481
15482        let project = self.project.clone();
15483
15484        cx.spawn_in(window, async move |_, cx| {
15485            let result = find_file(&buffer, project, buffer_position, cx).await;
15486
15487            if let Some((_, path)) = result {
15488                workspace
15489                    .update_in(cx, |workspace, window, cx| {
15490                        workspace.open_resolved_path(path, window, cx)
15491                    })?
15492                    .await?;
15493            }
15494            anyhow::Ok(())
15495        })
15496        .detach();
15497    }
15498
15499    pub(crate) fn navigate_to_hover_links(
15500        &mut self,
15501        kind: Option<GotoDefinitionKind>,
15502        mut definitions: Vec<HoverLink>,
15503        split: bool,
15504        window: &mut Window,
15505        cx: &mut Context<Editor>,
15506    ) -> Task<Result<Navigated>> {
15507        // If there is one definition, just open it directly
15508        if definitions.len() == 1 {
15509            let definition = definitions.pop().unwrap();
15510
15511            enum TargetTaskResult {
15512                Location(Option<Location>),
15513                AlreadyNavigated,
15514            }
15515
15516            let target_task = match definition {
15517                HoverLink::Text(link) => {
15518                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15519                }
15520                HoverLink::InlayHint(lsp_location, server_id) => {
15521                    let computation =
15522                        self.compute_target_location(lsp_location, server_id, window, cx);
15523                    cx.background_spawn(async move {
15524                        let location = computation.await?;
15525                        Ok(TargetTaskResult::Location(location))
15526                    })
15527                }
15528                HoverLink::Url(url) => {
15529                    cx.open_url(&url);
15530                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15531                }
15532                HoverLink::File(path) => {
15533                    if let Some(workspace) = self.workspace() {
15534                        cx.spawn_in(window, async move |_, cx| {
15535                            workspace
15536                                .update_in(cx, |workspace, window, cx| {
15537                                    workspace.open_resolved_path(path, window, cx)
15538                                })?
15539                                .await
15540                                .map(|_| TargetTaskResult::AlreadyNavigated)
15541                        })
15542                    } else {
15543                        Task::ready(Ok(TargetTaskResult::Location(None)))
15544                    }
15545                }
15546            };
15547            cx.spawn_in(window, async move |editor, cx| {
15548                let target = match target_task.await.context("target resolution task")? {
15549                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15550                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15551                    TargetTaskResult::Location(Some(target)) => target,
15552                };
15553
15554                editor.update_in(cx, |editor, window, cx| {
15555                    let Some(workspace) = editor.workspace() else {
15556                        return Navigated::No;
15557                    };
15558                    let pane = workspace.read(cx).active_pane().clone();
15559
15560                    let range = target.range.to_point(target.buffer.read(cx));
15561                    let range = editor.range_for_match(&range);
15562                    let range = collapse_multiline_range(range);
15563
15564                    if !split
15565                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15566                    {
15567                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15568                    } else {
15569                        window.defer(cx, move |window, cx| {
15570                            let target_editor: Entity<Self> =
15571                                workspace.update(cx, |workspace, cx| {
15572                                    let pane = if split {
15573                                        workspace.adjacent_pane(window, cx)
15574                                    } else {
15575                                        workspace.active_pane().clone()
15576                                    };
15577
15578                                    workspace.open_project_item(
15579                                        pane,
15580                                        target.buffer.clone(),
15581                                        true,
15582                                        true,
15583                                        window,
15584                                        cx,
15585                                    )
15586                                });
15587                            target_editor.update(cx, |target_editor, cx| {
15588                                // When selecting a definition in a different buffer, disable the nav history
15589                                // to avoid creating a history entry at the previous cursor location.
15590                                pane.update(cx, |pane, _| pane.disable_history());
15591                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15592                                pane.update(cx, |pane, _| pane.enable_history());
15593                            });
15594                        });
15595                    }
15596                    Navigated::Yes
15597                })
15598            })
15599        } else if !definitions.is_empty() {
15600            cx.spawn_in(window, async move |editor, cx| {
15601                let (title, location_tasks, workspace) = editor
15602                    .update_in(cx, |editor, window, cx| {
15603                        let tab_kind = match kind {
15604                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15605                            _ => "Definitions",
15606                        };
15607                        let title = definitions
15608                            .iter()
15609                            .find_map(|definition| match definition {
15610                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15611                                    let buffer = origin.buffer.read(cx);
15612                                    format!(
15613                                        "{} for {}",
15614                                        tab_kind,
15615                                        buffer
15616                                            .text_for_range(origin.range.clone())
15617                                            .collect::<String>()
15618                                    )
15619                                }),
15620                                HoverLink::InlayHint(_, _) => None,
15621                                HoverLink::Url(_) => None,
15622                                HoverLink::File(_) => None,
15623                            })
15624                            .unwrap_or(tab_kind.to_string());
15625                        let location_tasks = definitions
15626                            .into_iter()
15627                            .map(|definition| match definition {
15628                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15629                                HoverLink::InlayHint(lsp_location, server_id) => editor
15630                                    .compute_target_location(lsp_location, server_id, window, cx),
15631                                HoverLink::Url(_) => Task::ready(Ok(None)),
15632                                HoverLink::File(_) => Task::ready(Ok(None)),
15633                            })
15634                            .collect::<Vec<_>>();
15635                        (title, location_tasks, editor.workspace().clone())
15636                    })
15637                    .context("location tasks preparation")?;
15638
15639                let locations: Vec<Location> = future::join_all(location_tasks)
15640                    .await
15641                    .into_iter()
15642                    .filter_map(|location| location.transpose())
15643                    .collect::<Result<_>>()
15644                    .context("location tasks")?;
15645
15646                if locations.is_empty() {
15647                    return Ok(Navigated::No);
15648                }
15649
15650                let Some(workspace) = workspace else {
15651                    return Ok(Navigated::No);
15652                };
15653
15654                let opened = workspace
15655                    .update_in(cx, |workspace, window, cx| {
15656                        Self::open_locations_in_multibuffer(
15657                            workspace,
15658                            locations,
15659                            title,
15660                            split,
15661                            MultibufferSelectionMode::First,
15662                            window,
15663                            cx,
15664                        )
15665                    })
15666                    .ok();
15667
15668                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15669            })
15670        } else {
15671            Task::ready(Ok(Navigated::No))
15672        }
15673    }
15674
15675    fn compute_target_location(
15676        &self,
15677        lsp_location: lsp::Location,
15678        server_id: LanguageServerId,
15679        window: &mut Window,
15680        cx: &mut Context<Self>,
15681    ) -> Task<anyhow::Result<Option<Location>>> {
15682        let Some(project) = self.project.clone() else {
15683            return Task::ready(Ok(None));
15684        };
15685
15686        cx.spawn_in(window, async move |editor, cx| {
15687            let location_task = editor.update(cx, |_, cx| {
15688                project.update(cx, |project, cx| {
15689                    let language_server_name = project
15690                        .language_server_statuses(cx)
15691                        .find(|(id, _)| server_id == *id)
15692                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15693                    language_server_name.map(|language_server_name| {
15694                        project.open_local_buffer_via_lsp(
15695                            lsp_location.uri.clone(),
15696                            server_id,
15697                            language_server_name,
15698                            cx,
15699                        )
15700                    })
15701                })
15702            })?;
15703            let location = match location_task {
15704                Some(task) => Some({
15705                    let target_buffer_handle = task.await.context("open local buffer")?;
15706                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15707                        let target_start = target_buffer
15708                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15709                        let target_end = target_buffer
15710                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15711                        target_buffer.anchor_after(target_start)
15712                            ..target_buffer.anchor_before(target_end)
15713                    })?;
15714                    Location {
15715                        buffer: target_buffer_handle,
15716                        range,
15717                    }
15718                }),
15719                None => None,
15720            };
15721            Ok(location)
15722        })
15723    }
15724
15725    pub fn find_all_references(
15726        &mut self,
15727        _: &FindAllReferences,
15728        window: &mut Window,
15729        cx: &mut Context<Self>,
15730    ) -> Option<Task<Result<Navigated>>> {
15731        let selection = self.selections.newest::<usize>(cx);
15732        let multi_buffer = self.buffer.read(cx);
15733        let head = selection.head();
15734
15735        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15736        let head_anchor = multi_buffer_snapshot.anchor_at(
15737            head,
15738            if head < selection.tail() {
15739                Bias::Right
15740            } else {
15741                Bias::Left
15742            },
15743        );
15744
15745        match self
15746            .find_all_references_task_sources
15747            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15748        {
15749            Ok(_) => {
15750                log::info!(
15751                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15752                );
15753                return None;
15754            }
15755            Err(i) => {
15756                self.find_all_references_task_sources.insert(i, head_anchor);
15757            }
15758        }
15759
15760        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15761        let workspace = self.workspace()?;
15762        let project = workspace.read(cx).project().clone();
15763        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15764        Some(cx.spawn_in(window, async move |editor, cx| {
15765            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15766                if let Ok(i) = editor
15767                    .find_all_references_task_sources
15768                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15769                {
15770                    editor.find_all_references_task_sources.remove(i);
15771                }
15772            });
15773
15774            let locations = references.await?;
15775            if locations.is_empty() {
15776                return anyhow::Ok(Navigated::No);
15777            }
15778
15779            workspace.update_in(cx, |workspace, window, cx| {
15780                let title = locations
15781                    .first()
15782                    .as_ref()
15783                    .map(|location| {
15784                        let buffer = location.buffer.read(cx);
15785                        format!(
15786                            "References to `{}`",
15787                            buffer
15788                                .text_for_range(location.range.clone())
15789                                .collect::<String>()
15790                        )
15791                    })
15792                    .unwrap();
15793                Self::open_locations_in_multibuffer(
15794                    workspace,
15795                    locations,
15796                    title,
15797                    false,
15798                    MultibufferSelectionMode::First,
15799                    window,
15800                    cx,
15801                );
15802                Navigated::Yes
15803            })
15804        }))
15805    }
15806
15807    /// Opens a multibuffer with the given project locations in it
15808    pub fn open_locations_in_multibuffer(
15809        workspace: &mut Workspace,
15810        mut locations: Vec<Location>,
15811        title: String,
15812        split: bool,
15813        multibuffer_selection_mode: MultibufferSelectionMode,
15814        window: &mut Window,
15815        cx: &mut Context<Workspace>,
15816    ) {
15817        if locations.is_empty() {
15818            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15819            return;
15820        }
15821
15822        // If there are multiple definitions, open them in a multibuffer
15823        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15824        let mut locations = locations.into_iter().peekable();
15825        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15826        let capability = workspace.project().read(cx).capability();
15827
15828        let excerpt_buffer = cx.new(|cx| {
15829            let mut multibuffer = MultiBuffer::new(capability);
15830            while let Some(location) = locations.next() {
15831                let buffer = location.buffer.read(cx);
15832                let mut ranges_for_buffer = Vec::new();
15833                let range = location.range.to_point(buffer);
15834                ranges_for_buffer.push(range.clone());
15835
15836                while let Some(next_location) = locations.peek() {
15837                    if next_location.buffer == location.buffer {
15838                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15839                        locations.next();
15840                    } else {
15841                        break;
15842                    }
15843                }
15844
15845                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15846                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15847                    PathKey::for_buffer(&location.buffer, cx),
15848                    location.buffer.clone(),
15849                    ranges_for_buffer,
15850                    DEFAULT_MULTIBUFFER_CONTEXT,
15851                    cx,
15852                );
15853                ranges.extend(new_ranges)
15854            }
15855
15856            multibuffer.with_title(title)
15857        });
15858
15859        let editor = cx.new(|cx| {
15860            Editor::for_multibuffer(
15861                excerpt_buffer,
15862                Some(workspace.project().clone()),
15863                window,
15864                cx,
15865            )
15866        });
15867        editor.update(cx, |editor, cx| {
15868            match multibuffer_selection_mode {
15869                MultibufferSelectionMode::First => {
15870                    if let Some(first_range) = ranges.first() {
15871                        editor.change_selections(
15872                            SelectionEffects::no_scroll(),
15873                            window,
15874                            cx,
15875                            |selections| {
15876                                selections.clear_disjoint();
15877                                selections
15878                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15879                            },
15880                        );
15881                    }
15882                    editor.highlight_background::<Self>(
15883                        &ranges,
15884                        |theme| theme.colors().editor_highlighted_line_background,
15885                        cx,
15886                    );
15887                }
15888                MultibufferSelectionMode::All => {
15889                    editor.change_selections(
15890                        SelectionEffects::no_scroll(),
15891                        window,
15892                        cx,
15893                        |selections| {
15894                            selections.clear_disjoint();
15895                            selections.select_anchor_ranges(ranges);
15896                        },
15897                    );
15898                }
15899            }
15900            editor.register_buffers_with_language_servers(cx);
15901        });
15902
15903        let item = Box::new(editor);
15904        let item_id = item.item_id();
15905
15906        if split {
15907            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15908        } else {
15909            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15910                let (preview_item_id, preview_item_idx) =
15911                    workspace.active_pane().read_with(cx, |pane, _| {
15912                        (pane.preview_item_id(), pane.preview_item_idx())
15913                    });
15914
15915                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15916
15917                if let Some(preview_item_id) = preview_item_id {
15918                    workspace.active_pane().update(cx, |pane, cx| {
15919                        pane.remove_item(preview_item_id, false, false, window, cx);
15920                    });
15921                }
15922            } else {
15923                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15924            }
15925        }
15926        workspace.active_pane().update(cx, |pane, cx| {
15927            pane.set_preview_item_id(Some(item_id), cx);
15928        });
15929    }
15930
15931    pub fn rename(
15932        &mut self,
15933        _: &Rename,
15934        window: &mut Window,
15935        cx: &mut Context<Self>,
15936    ) -> Option<Task<Result<()>>> {
15937        use language::ToOffset as _;
15938
15939        let provider = self.semantics_provider.clone()?;
15940        let selection = self.selections.newest_anchor().clone();
15941        let (cursor_buffer, cursor_buffer_position) = self
15942            .buffer
15943            .read(cx)
15944            .text_anchor_for_position(selection.head(), cx)?;
15945        let (tail_buffer, cursor_buffer_position_end) = self
15946            .buffer
15947            .read(cx)
15948            .text_anchor_for_position(selection.tail(), cx)?;
15949        if tail_buffer != cursor_buffer {
15950            return None;
15951        }
15952
15953        let snapshot = cursor_buffer.read(cx).snapshot();
15954        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15955        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15956        let prepare_rename = provider
15957            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15958            .unwrap_or_else(|| Task::ready(Ok(None)));
15959        drop(snapshot);
15960
15961        Some(cx.spawn_in(window, async move |this, cx| {
15962            let rename_range = if let Some(range) = prepare_rename.await? {
15963                Some(range)
15964            } else {
15965                this.update(cx, |this, cx| {
15966                    let buffer = this.buffer.read(cx).snapshot(cx);
15967                    let mut buffer_highlights = this
15968                        .document_highlights_for_position(selection.head(), &buffer)
15969                        .filter(|highlight| {
15970                            highlight.start.excerpt_id == selection.head().excerpt_id
15971                                && highlight.end.excerpt_id == selection.head().excerpt_id
15972                        });
15973                    buffer_highlights
15974                        .next()
15975                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15976                })?
15977            };
15978            if let Some(rename_range) = rename_range {
15979                this.update_in(cx, |this, window, cx| {
15980                    let snapshot = cursor_buffer.read(cx).snapshot();
15981                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15982                    let cursor_offset_in_rename_range =
15983                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15984                    let cursor_offset_in_rename_range_end =
15985                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15986
15987                    this.take_rename(false, window, cx);
15988                    let buffer = this.buffer.read(cx).read(cx);
15989                    let cursor_offset = selection.head().to_offset(&buffer);
15990                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15991                    let rename_end = rename_start + rename_buffer_range.len();
15992                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15993                    let mut old_highlight_id = None;
15994                    let old_name: Arc<str> = buffer
15995                        .chunks(rename_start..rename_end, true)
15996                        .map(|chunk| {
15997                            if old_highlight_id.is_none() {
15998                                old_highlight_id = chunk.syntax_highlight_id;
15999                            }
16000                            chunk.text
16001                        })
16002                        .collect::<String>()
16003                        .into();
16004
16005                    drop(buffer);
16006
16007                    // Position the selection in the rename editor so that it matches the current selection.
16008                    this.show_local_selections = false;
16009                    let rename_editor = cx.new(|cx| {
16010                        let mut editor = Editor::single_line(window, cx);
16011                        editor.buffer.update(cx, |buffer, cx| {
16012                            buffer.edit([(0..0, old_name.clone())], None, cx)
16013                        });
16014                        let rename_selection_range = match cursor_offset_in_rename_range
16015                            .cmp(&cursor_offset_in_rename_range_end)
16016                        {
16017                            Ordering::Equal => {
16018                                editor.select_all(&SelectAll, window, cx);
16019                                return editor;
16020                            }
16021                            Ordering::Less => {
16022                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16023                            }
16024                            Ordering::Greater => {
16025                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16026                            }
16027                        };
16028                        if rename_selection_range.end > old_name.len() {
16029                            editor.select_all(&SelectAll, window, cx);
16030                        } else {
16031                            editor.change_selections(Default::default(), window, cx, |s| {
16032                                s.select_ranges([rename_selection_range]);
16033                            });
16034                        }
16035                        editor
16036                    });
16037                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16038                        if e == &EditorEvent::Focused {
16039                            cx.emit(EditorEvent::FocusedIn)
16040                        }
16041                    })
16042                    .detach();
16043
16044                    let write_highlights =
16045                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16046                    let read_highlights =
16047                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16048                    let ranges = write_highlights
16049                        .iter()
16050                        .flat_map(|(_, ranges)| ranges.iter())
16051                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16052                        .cloned()
16053                        .collect();
16054
16055                    this.highlight_text::<Rename>(
16056                        ranges,
16057                        HighlightStyle {
16058                            fade_out: Some(0.6),
16059                            ..Default::default()
16060                        },
16061                        cx,
16062                    );
16063                    let rename_focus_handle = rename_editor.focus_handle(cx);
16064                    window.focus(&rename_focus_handle);
16065                    let block_id = this.insert_blocks(
16066                        [BlockProperties {
16067                            style: BlockStyle::Flex,
16068                            placement: BlockPlacement::Below(range.start),
16069                            height: Some(1),
16070                            render: Arc::new({
16071                                let rename_editor = rename_editor.clone();
16072                                move |cx: &mut BlockContext| {
16073                                    let mut text_style = cx.editor_style.text.clone();
16074                                    if let Some(highlight_style) = old_highlight_id
16075                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16076                                    {
16077                                        text_style = text_style.highlight(highlight_style);
16078                                    }
16079                                    div()
16080                                        .block_mouse_except_scroll()
16081                                        .pl(cx.anchor_x)
16082                                        .child(EditorElement::new(
16083                                            &rename_editor,
16084                                            EditorStyle {
16085                                                background: cx.theme().system().transparent,
16086                                                local_player: cx.editor_style.local_player,
16087                                                text: text_style,
16088                                                scrollbar_width: cx.editor_style.scrollbar_width,
16089                                                syntax: cx.editor_style.syntax.clone(),
16090                                                status: cx.editor_style.status.clone(),
16091                                                inlay_hints_style: HighlightStyle {
16092                                                    font_weight: Some(FontWeight::BOLD),
16093                                                    ..make_inlay_hints_style(cx.app)
16094                                                },
16095                                                inline_completion_styles: make_suggestion_styles(
16096                                                    cx.app,
16097                                                ),
16098                                                ..EditorStyle::default()
16099                                            },
16100                                        ))
16101                                        .into_any_element()
16102                                }
16103                            }),
16104                            priority: 0,
16105                            render_in_minimap: true,
16106                        }],
16107                        Some(Autoscroll::fit()),
16108                        cx,
16109                    )[0];
16110                    this.pending_rename = Some(RenameState {
16111                        range,
16112                        old_name,
16113                        editor: rename_editor,
16114                        block_id,
16115                    });
16116                })?;
16117            }
16118
16119            Ok(())
16120        }))
16121    }
16122
16123    pub fn confirm_rename(
16124        &mut self,
16125        _: &ConfirmRename,
16126        window: &mut Window,
16127        cx: &mut Context<Self>,
16128    ) -> Option<Task<Result<()>>> {
16129        let rename = self.take_rename(false, window, cx)?;
16130        let workspace = self.workspace()?.downgrade();
16131        let (buffer, start) = self
16132            .buffer
16133            .read(cx)
16134            .text_anchor_for_position(rename.range.start, cx)?;
16135        let (end_buffer, _) = self
16136            .buffer
16137            .read(cx)
16138            .text_anchor_for_position(rename.range.end, cx)?;
16139        if buffer != end_buffer {
16140            return None;
16141        }
16142
16143        let old_name = rename.old_name;
16144        let new_name = rename.editor.read(cx).text(cx);
16145
16146        let rename = self.semantics_provider.as_ref()?.perform_rename(
16147            &buffer,
16148            start,
16149            new_name.clone(),
16150            cx,
16151        )?;
16152
16153        Some(cx.spawn_in(window, async move |editor, cx| {
16154            let project_transaction = rename.await?;
16155            Self::open_project_transaction(
16156                &editor,
16157                workspace,
16158                project_transaction,
16159                format!("Rename: {}{}", old_name, new_name),
16160                cx,
16161            )
16162            .await?;
16163
16164            editor.update(cx, |editor, cx| {
16165                editor.refresh_document_highlights(cx);
16166            })?;
16167            Ok(())
16168        }))
16169    }
16170
16171    fn take_rename(
16172        &mut self,
16173        moving_cursor: bool,
16174        window: &mut Window,
16175        cx: &mut Context<Self>,
16176    ) -> Option<RenameState> {
16177        let rename = self.pending_rename.take()?;
16178        if rename.editor.focus_handle(cx).is_focused(window) {
16179            window.focus(&self.focus_handle);
16180        }
16181
16182        self.remove_blocks(
16183            [rename.block_id].into_iter().collect(),
16184            Some(Autoscroll::fit()),
16185            cx,
16186        );
16187        self.clear_highlights::<Rename>(cx);
16188        self.show_local_selections = true;
16189
16190        if moving_cursor {
16191            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16192                editor.selections.newest::<usize>(cx).head()
16193            });
16194
16195            // Update the selection to match the position of the selection inside
16196            // the rename editor.
16197            let snapshot = self.buffer.read(cx).read(cx);
16198            let rename_range = rename.range.to_offset(&snapshot);
16199            let cursor_in_editor = snapshot
16200                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16201                .min(rename_range.end);
16202            drop(snapshot);
16203
16204            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16205                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16206            });
16207        } else {
16208            self.refresh_document_highlights(cx);
16209        }
16210
16211        Some(rename)
16212    }
16213
16214    pub fn pending_rename(&self) -> Option<&RenameState> {
16215        self.pending_rename.as_ref()
16216    }
16217
16218    fn format(
16219        &mut self,
16220        _: &Format,
16221        window: &mut Window,
16222        cx: &mut Context<Self>,
16223    ) -> Option<Task<Result<()>>> {
16224        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16225
16226        let project = match &self.project {
16227            Some(project) => project.clone(),
16228            None => return None,
16229        };
16230
16231        Some(self.perform_format(
16232            project,
16233            FormatTrigger::Manual,
16234            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16235            window,
16236            cx,
16237        ))
16238    }
16239
16240    fn format_selections(
16241        &mut self,
16242        _: &FormatSelections,
16243        window: &mut Window,
16244        cx: &mut Context<Self>,
16245    ) -> Option<Task<Result<()>>> {
16246        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16247
16248        let project = match &self.project {
16249            Some(project) => project.clone(),
16250            None => return None,
16251        };
16252
16253        let ranges = self
16254            .selections
16255            .all_adjusted(cx)
16256            .into_iter()
16257            .map(|selection| selection.range())
16258            .collect_vec();
16259
16260        Some(self.perform_format(
16261            project,
16262            FormatTrigger::Manual,
16263            FormatTarget::Ranges(ranges),
16264            window,
16265            cx,
16266        ))
16267    }
16268
16269    fn perform_format(
16270        &mut self,
16271        project: Entity<Project>,
16272        trigger: FormatTrigger,
16273        target: FormatTarget,
16274        window: &mut Window,
16275        cx: &mut Context<Self>,
16276    ) -> Task<Result<()>> {
16277        let buffer = self.buffer.clone();
16278        let (buffers, target) = match target {
16279            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16280            FormatTarget::Ranges(selection_ranges) => {
16281                let multi_buffer = buffer.read(cx);
16282                let snapshot = multi_buffer.read(cx);
16283                let mut buffers = HashSet::default();
16284                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16285                    BTreeMap::new();
16286                for selection_range in selection_ranges {
16287                    for (buffer, buffer_range, _) in
16288                        snapshot.range_to_buffer_ranges(selection_range)
16289                    {
16290                        let buffer_id = buffer.remote_id();
16291                        let start = buffer.anchor_before(buffer_range.start);
16292                        let end = buffer.anchor_after(buffer_range.end);
16293                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16294                        buffer_id_to_ranges
16295                            .entry(buffer_id)
16296                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16297                            .or_insert_with(|| vec![start..end]);
16298                    }
16299                }
16300                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16301            }
16302        };
16303
16304        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16305        let selections_prev = transaction_id_prev
16306            .and_then(|transaction_id_prev| {
16307                // default to selections as they were after the last edit, if we have them,
16308                // instead of how they are now.
16309                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16310                // will take you back to where you made the last edit, instead of staying where you scrolled
16311                self.selection_history
16312                    .transaction(transaction_id_prev)
16313                    .map(|t| t.0.clone())
16314            })
16315            .unwrap_or_else(|| {
16316                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16317                self.selections.disjoint_anchors()
16318            });
16319
16320        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16321        let format = project.update(cx, |project, cx| {
16322            project.format(buffers, target, true, trigger, cx)
16323        });
16324
16325        cx.spawn_in(window, async move |editor, cx| {
16326            let transaction = futures::select_biased! {
16327                transaction = format.log_err().fuse() => transaction,
16328                () = timeout => {
16329                    log::warn!("timed out waiting for formatting");
16330                    None
16331                }
16332            };
16333
16334            buffer
16335                .update(cx, |buffer, cx| {
16336                    if let Some(transaction) = transaction {
16337                        if !buffer.is_singleton() {
16338                            buffer.push_transaction(&transaction.0, cx);
16339                        }
16340                    }
16341                    cx.notify();
16342                })
16343                .ok();
16344
16345            if let Some(transaction_id_now) =
16346                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16347            {
16348                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16349                if has_new_transaction {
16350                    _ = editor.update(cx, |editor, _| {
16351                        editor
16352                            .selection_history
16353                            .insert_transaction(transaction_id_now, selections_prev);
16354                    });
16355                }
16356            }
16357
16358            Ok(())
16359        })
16360    }
16361
16362    fn organize_imports(
16363        &mut self,
16364        _: &OrganizeImports,
16365        window: &mut Window,
16366        cx: &mut Context<Self>,
16367    ) -> Option<Task<Result<()>>> {
16368        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16369        let project = match &self.project {
16370            Some(project) => project.clone(),
16371            None => return None,
16372        };
16373        Some(self.perform_code_action_kind(
16374            project,
16375            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16376            window,
16377            cx,
16378        ))
16379    }
16380
16381    fn perform_code_action_kind(
16382        &mut self,
16383        project: Entity<Project>,
16384        kind: CodeActionKind,
16385        window: &mut Window,
16386        cx: &mut Context<Self>,
16387    ) -> Task<Result<()>> {
16388        let buffer = self.buffer.clone();
16389        let buffers = buffer.read(cx).all_buffers();
16390        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16391        let apply_action = project.update(cx, |project, cx| {
16392            project.apply_code_action_kind(buffers, kind, true, cx)
16393        });
16394        cx.spawn_in(window, async move |_, cx| {
16395            let transaction = futures::select_biased! {
16396                () = timeout => {
16397                    log::warn!("timed out waiting for executing code action");
16398                    None
16399                }
16400                transaction = apply_action.log_err().fuse() => transaction,
16401            };
16402            buffer
16403                .update(cx, |buffer, cx| {
16404                    // check if we need this
16405                    if let Some(transaction) = transaction {
16406                        if !buffer.is_singleton() {
16407                            buffer.push_transaction(&transaction.0, cx);
16408                        }
16409                    }
16410                    cx.notify();
16411                })
16412                .ok();
16413            Ok(())
16414        })
16415    }
16416
16417    pub fn restart_language_server(
16418        &mut self,
16419        _: &RestartLanguageServer,
16420        _: &mut Window,
16421        cx: &mut Context<Self>,
16422    ) {
16423        if let Some(project) = self.project.clone() {
16424            self.buffer.update(cx, |multi_buffer, cx| {
16425                project.update(cx, |project, cx| {
16426                    project.restart_language_servers_for_buffers(
16427                        multi_buffer.all_buffers().into_iter().collect(),
16428                        HashSet::default(),
16429                        cx,
16430                    );
16431                });
16432            })
16433        }
16434    }
16435
16436    pub fn stop_language_server(
16437        &mut self,
16438        _: &StopLanguageServer,
16439        _: &mut Window,
16440        cx: &mut Context<Self>,
16441    ) {
16442        if let Some(project) = self.project.clone() {
16443            self.buffer.update(cx, |multi_buffer, cx| {
16444                project.update(cx, |project, cx| {
16445                    project.stop_language_servers_for_buffers(
16446                        multi_buffer.all_buffers().into_iter().collect(),
16447                        HashSet::default(),
16448                        cx,
16449                    );
16450                    cx.emit(project::Event::RefreshInlayHints);
16451                });
16452            });
16453        }
16454    }
16455
16456    fn cancel_language_server_work(
16457        workspace: &mut Workspace,
16458        _: &actions::CancelLanguageServerWork,
16459        _: &mut Window,
16460        cx: &mut Context<Workspace>,
16461    ) {
16462        let project = workspace.project();
16463        let buffers = workspace
16464            .active_item(cx)
16465            .and_then(|item| item.act_as::<Editor>(cx))
16466            .map_or(HashSet::default(), |editor| {
16467                editor.read(cx).buffer.read(cx).all_buffers()
16468            });
16469        project.update(cx, |project, cx| {
16470            project.cancel_language_server_work_for_buffers(buffers, cx);
16471        });
16472    }
16473
16474    fn show_character_palette(
16475        &mut self,
16476        _: &ShowCharacterPalette,
16477        window: &mut Window,
16478        _: &mut Context<Self>,
16479    ) {
16480        window.show_character_palette();
16481    }
16482
16483    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16484        if !self.diagnostics_enabled() {
16485            return;
16486        }
16487
16488        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16489            let buffer = self.buffer.read(cx).snapshot(cx);
16490            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16491            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16492            let is_valid = buffer
16493                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16494                .any(|entry| {
16495                    entry.diagnostic.is_primary
16496                        && !entry.range.is_empty()
16497                        && entry.range.start == primary_range_start
16498                        && entry.diagnostic.message == active_diagnostics.active_message
16499                });
16500
16501            if !is_valid {
16502                self.dismiss_diagnostics(cx);
16503            }
16504        }
16505    }
16506
16507    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16508        match &self.active_diagnostics {
16509            ActiveDiagnostic::Group(group) => Some(group),
16510            _ => None,
16511        }
16512    }
16513
16514    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16515        if !self.diagnostics_enabled() {
16516            return;
16517        }
16518        self.dismiss_diagnostics(cx);
16519        self.active_diagnostics = ActiveDiagnostic::All;
16520    }
16521
16522    fn activate_diagnostics(
16523        &mut self,
16524        buffer_id: BufferId,
16525        diagnostic: DiagnosticEntry<usize>,
16526        window: &mut Window,
16527        cx: &mut Context<Self>,
16528    ) {
16529        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16530            return;
16531        }
16532        self.dismiss_diagnostics(cx);
16533        let snapshot = self.snapshot(window, cx);
16534        let buffer = self.buffer.read(cx).snapshot(cx);
16535        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16536            return;
16537        };
16538
16539        let diagnostic_group = buffer
16540            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16541            .collect::<Vec<_>>();
16542
16543        let blocks =
16544            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16545
16546        let blocks = self.display_map.update(cx, |display_map, cx| {
16547            display_map.insert_blocks(blocks, cx).into_iter().collect()
16548        });
16549        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16550            active_range: buffer.anchor_before(diagnostic.range.start)
16551                ..buffer.anchor_after(diagnostic.range.end),
16552            active_message: diagnostic.diagnostic.message.clone(),
16553            group_id: diagnostic.diagnostic.group_id,
16554            blocks,
16555        });
16556        cx.notify();
16557    }
16558
16559    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16560        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16561            return;
16562        };
16563
16564        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16565        if let ActiveDiagnostic::Group(group) = prev {
16566            self.display_map.update(cx, |display_map, cx| {
16567                display_map.remove_blocks(group.blocks, cx);
16568            });
16569            cx.notify();
16570        }
16571    }
16572
16573    /// Disable inline diagnostics rendering for this editor.
16574    pub fn disable_inline_diagnostics(&mut self) {
16575        self.inline_diagnostics_enabled = false;
16576        self.inline_diagnostics_update = Task::ready(());
16577        self.inline_diagnostics.clear();
16578    }
16579
16580    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16581        self.diagnostics_enabled = false;
16582        self.dismiss_diagnostics(cx);
16583        self.inline_diagnostics_update = Task::ready(());
16584        self.inline_diagnostics.clear();
16585    }
16586
16587    pub fn diagnostics_enabled(&self) -> bool {
16588        self.diagnostics_enabled && self.mode.is_full()
16589    }
16590
16591    pub fn inline_diagnostics_enabled(&self) -> bool {
16592        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16593    }
16594
16595    pub fn show_inline_diagnostics(&self) -> bool {
16596        self.show_inline_diagnostics
16597    }
16598
16599    pub fn toggle_inline_diagnostics(
16600        &mut self,
16601        _: &ToggleInlineDiagnostics,
16602        window: &mut Window,
16603        cx: &mut Context<Editor>,
16604    ) {
16605        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16606        self.refresh_inline_diagnostics(false, window, cx);
16607    }
16608
16609    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16610        self.diagnostics_max_severity = severity;
16611        self.display_map.update(cx, |display_map, _| {
16612            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16613        });
16614    }
16615
16616    pub fn toggle_diagnostics(
16617        &mut self,
16618        _: &ToggleDiagnostics,
16619        window: &mut Window,
16620        cx: &mut Context<Editor>,
16621    ) {
16622        if !self.diagnostics_enabled() {
16623            return;
16624        }
16625
16626        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16627            EditorSettings::get_global(cx)
16628                .diagnostics_max_severity
16629                .filter(|severity| severity != &DiagnosticSeverity::Off)
16630                .unwrap_or(DiagnosticSeverity::Hint)
16631        } else {
16632            DiagnosticSeverity::Off
16633        };
16634        self.set_max_diagnostics_severity(new_severity, cx);
16635        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16636            self.active_diagnostics = ActiveDiagnostic::None;
16637            self.inline_diagnostics_update = Task::ready(());
16638            self.inline_diagnostics.clear();
16639        } else {
16640            self.refresh_inline_diagnostics(false, window, cx);
16641        }
16642
16643        cx.notify();
16644    }
16645
16646    pub fn toggle_minimap(
16647        &mut self,
16648        _: &ToggleMinimap,
16649        window: &mut Window,
16650        cx: &mut Context<Editor>,
16651    ) {
16652        if self.supports_minimap(cx) {
16653            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16654        }
16655    }
16656
16657    fn refresh_inline_diagnostics(
16658        &mut self,
16659        debounce: bool,
16660        window: &mut Window,
16661        cx: &mut Context<Self>,
16662    ) {
16663        let max_severity = ProjectSettings::get_global(cx)
16664            .diagnostics
16665            .inline
16666            .max_severity
16667            .unwrap_or(self.diagnostics_max_severity);
16668
16669        if !self.inline_diagnostics_enabled()
16670            || !self.show_inline_diagnostics
16671            || max_severity == DiagnosticSeverity::Off
16672        {
16673            self.inline_diagnostics_update = Task::ready(());
16674            self.inline_diagnostics.clear();
16675            return;
16676        }
16677
16678        let debounce_ms = ProjectSettings::get_global(cx)
16679            .diagnostics
16680            .inline
16681            .update_debounce_ms;
16682        let debounce = if debounce && debounce_ms > 0 {
16683            Some(Duration::from_millis(debounce_ms))
16684        } else {
16685            None
16686        };
16687        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16688            if let Some(debounce) = debounce {
16689                cx.background_executor().timer(debounce).await;
16690            }
16691            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16692                editor
16693                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16694                    .ok()
16695            }) else {
16696                return;
16697            };
16698
16699            let new_inline_diagnostics = cx
16700                .background_spawn(async move {
16701                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16702                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16703                        let message = diagnostic_entry
16704                            .diagnostic
16705                            .message
16706                            .split_once('\n')
16707                            .map(|(line, _)| line)
16708                            .map(SharedString::new)
16709                            .unwrap_or_else(|| {
16710                                SharedString::from(diagnostic_entry.diagnostic.message)
16711                            });
16712                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16713                        let (Ok(i) | Err(i)) = inline_diagnostics
16714                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16715                        inline_diagnostics.insert(
16716                            i,
16717                            (
16718                                start_anchor,
16719                                InlineDiagnostic {
16720                                    message,
16721                                    group_id: diagnostic_entry.diagnostic.group_id,
16722                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16723                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16724                                    severity: diagnostic_entry.diagnostic.severity,
16725                                },
16726                            ),
16727                        );
16728                    }
16729                    inline_diagnostics
16730                })
16731                .await;
16732
16733            editor
16734                .update(cx, |editor, cx| {
16735                    editor.inline_diagnostics = new_inline_diagnostics;
16736                    cx.notify();
16737                })
16738                .ok();
16739        });
16740    }
16741
16742    fn pull_diagnostics(
16743        &mut self,
16744        buffer_id: Option<BufferId>,
16745        window: &Window,
16746        cx: &mut Context<Self>,
16747    ) -> Option<()> {
16748        if !self.mode().is_full() {
16749            return None;
16750        }
16751        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16752            .diagnostics
16753            .lsp_pull_diagnostics;
16754        if !pull_diagnostics_settings.enabled {
16755            return None;
16756        }
16757        let project = self.project.as_ref()?.downgrade();
16758        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16759        let mut buffers = self.buffer.read(cx).all_buffers();
16760        if let Some(buffer_id) = buffer_id {
16761            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16762        }
16763
16764        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16765            cx.background_executor().timer(debounce).await;
16766
16767            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16768                buffers
16769                    .into_iter()
16770                    .filter_map(|buffer| {
16771                        project
16772                            .update(cx, |project, cx| {
16773                                project.lsp_store().update(cx, |lsp_store, cx| {
16774                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16775                                })
16776                            })
16777                            .ok()
16778                    })
16779                    .collect::<FuturesUnordered<_>>()
16780            }) else {
16781                return;
16782            };
16783
16784            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16785                match pull_task {
16786                    Ok(()) => {
16787                        if editor
16788                            .update_in(cx, |editor, window, cx| {
16789                                editor.update_diagnostics_state(window, cx);
16790                            })
16791                            .is_err()
16792                        {
16793                            return;
16794                        }
16795                    }
16796                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16797                }
16798            }
16799        });
16800
16801        Some(())
16802    }
16803
16804    pub fn set_selections_from_remote(
16805        &mut self,
16806        selections: Vec<Selection<Anchor>>,
16807        pending_selection: Option<Selection<Anchor>>,
16808        window: &mut Window,
16809        cx: &mut Context<Self>,
16810    ) {
16811        let old_cursor_position = self.selections.newest_anchor().head();
16812        self.selections.change_with(cx, |s| {
16813            s.select_anchors(selections);
16814            if let Some(pending_selection) = pending_selection {
16815                s.set_pending(pending_selection, SelectMode::Character);
16816            } else {
16817                s.clear_pending();
16818            }
16819        });
16820        self.selections_did_change(
16821            false,
16822            &old_cursor_position,
16823            SelectionEffects::default(),
16824            window,
16825            cx,
16826        );
16827    }
16828
16829    pub fn transact(
16830        &mut self,
16831        window: &mut Window,
16832        cx: &mut Context<Self>,
16833        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16834    ) -> Option<TransactionId> {
16835        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16836            this.start_transaction_at(Instant::now(), window, cx);
16837            update(this, window, cx);
16838            this.end_transaction_at(Instant::now(), cx)
16839        })
16840    }
16841
16842    pub fn start_transaction_at(
16843        &mut self,
16844        now: Instant,
16845        window: &mut Window,
16846        cx: &mut Context<Self>,
16847    ) {
16848        self.end_selection(window, cx);
16849        if let Some(tx_id) = self
16850            .buffer
16851            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16852        {
16853            self.selection_history
16854                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16855            cx.emit(EditorEvent::TransactionBegun {
16856                transaction_id: tx_id,
16857            })
16858        }
16859    }
16860
16861    pub fn end_transaction_at(
16862        &mut self,
16863        now: Instant,
16864        cx: &mut Context<Self>,
16865    ) -> Option<TransactionId> {
16866        if let Some(transaction_id) = self
16867            .buffer
16868            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16869        {
16870            if let Some((_, end_selections)) =
16871                self.selection_history.transaction_mut(transaction_id)
16872            {
16873                *end_selections = Some(self.selections.disjoint_anchors());
16874            } else {
16875                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16876            }
16877
16878            cx.emit(EditorEvent::Edited { transaction_id });
16879            Some(transaction_id)
16880        } else {
16881            None
16882        }
16883    }
16884
16885    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16886        if self.selection_mark_mode {
16887            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16888                s.move_with(|_, sel| {
16889                    sel.collapse_to(sel.head(), SelectionGoal::None);
16890                });
16891            })
16892        }
16893        self.selection_mark_mode = true;
16894        cx.notify();
16895    }
16896
16897    pub fn swap_selection_ends(
16898        &mut self,
16899        _: &actions::SwapSelectionEnds,
16900        window: &mut Window,
16901        cx: &mut Context<Self>,
16902    ) {
16903        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16904            s.move_with(|_, sel| {
16905                if sel.start != sel.end {
16906                    sel.reversed = !sel.reversed
16907                }
16908            });
16909        });
16910        self.request_autoscroll(Autoscroll::newest(), cx);
16911        cx.notify();
16912    }
16913
16914    pub fn toggle_fold(
16915        &mut self,
16916        _: &actions::ToggleFold,
16917        window: &mut Window,
16918        cx: &mut Context<Self>,
16919    ) {
16920        if self.is_singleton(cx) {
16921            let selection = self.selections.newest::<Point>(cx);
16922
16923            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16924            let range = if selection.is_empty() {
16925                let point = selection.head().to_display_point(&display_map);
16926                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16927                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16928                    .to_point(&display_map);
16929                start..end
16930            } else {
16931                selection.range()
16932            };
16933            if display_map.folds_in_range(range).next().is_some() {
16934                self.unfold_lines(&Default::default(), window, cx)
16935            } else {
16936                self.fold(&Default::default(), window, cx)
16937            }
16938        } else {
16939            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16940            let buffer_ids: HashSet<_> = self
16941                .selections
16942                .disjoint_anchor_ranges()
16943                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16944                .collect();
16945
16946            let should_unfold = buffer_ids
16947                .iter()
16948                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16949
16950            for buffer_id in buffer_ids {
16951                if should_unfold {
16952                    self.unfold_buffer(buffer_id, cx);
16953                } else {
16954                    self.fold_buffer(buffer_id, cx);
16955                }
16956            }
16957        }
16958    }
16959
16960    pub fn toggle_fold_recursive(
16961        &mut self,
16962        _: &actions::ToggleFoldRecursive,
16963        window: &mut Window,
16964        cx: &mut Context<Self>,
16965    ) {
16966        let selection = self.selections.newest::<Point>(cx);
16967
16968        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16969        let range = if selection.is_empty() {
16970            let point = selection.head().to_display_point(&display_map);
16971            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16972            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16973                .to_point(&display_map);
16974            start..end
16975        } else {
16976            selection.range()
16977        };
16978        if display_map.folds_in_range(range).next().is_some() {
16979            self.unfold_recursive(&Default::default(), window, cx)
16980        } else {
16981            self.fold_recursive(&Default::default(), window, cx)
16982        }
16983    }
16984
16985    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16986        if self.is_singleton(cx) {
16987            let mut to_fold = Vec::new();
16988            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16989            let selections = self.selections.all_adjusted(cx);
16990
16991            for selection in selections {
16992                let range = selection.range().sorted();
16993                let buffer_start_row = range.start.row;
16994
16995                if range.start.row != range.end.row {
16996                    let mut found = false;
16997                    let mut row = range.start.row;
16998                    while row <= range.end.row {
16999                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17000                        {
17001                            found = true;
17002                            row = crease.range().end.row + 1;
17003                            to_fold.push(crease);
17004                        } else {
17005                            row += 1
17006                        }
17007                    }
17008                    if found {
17009                        continue;
17010                    }
17011                }
17012
17013                for row in (0..=range.start.row).rev() {
17014                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17015                        if crease.range().end.row >= buffer_start_row {
17016                            to_fold.push(crease);
17017                            if row <= range.start.row {
17018                                break;
17019                            }
17020                        }
17021                    }
17022                }
17023            }
17024
17025            self.fold_creases(to_fold, true, window, cx);
17026        } else {
17027            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17028            let buffer_ids = self
17029                .selections
17030                .disjoint_anchor_ranges()
17031                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17032                .collect::<HashSet<_>>();
17033            for buffer_id in buffer_ids {
17034                self.fold_buffer(buffer_id, cx);
17035            }
17036        }
17037    }
17038
17039    fn fold_at_level(
17040        &mut self,
17041        fold_at: &FoldAtLevel,
17042        window: &mut Window,
17043        cx: &mut Context<Self>,
17044    ) {
17045        if !self.buffer.read(cx).is_singleton() {
17046            return;
17047        }
17048
17049        let fold_at_level = fold_at.0;
17050        let snapshot = self.buffer.read(cx).snapshot(cx);
17051        let mut to_fold = Vec::new();
17052        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17053
17054        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17055            while start_row < end_row {
17056                match self
17057                    .snapshot(window, cx)
17058                    .crease_for_buffer_row(MultiBufferRow(start_row))
17059                {
17060                    Some(crease) => {
17061                        let nested_start_row = crease.range().start.row + 1;
17062                        let nested_end_row = crease.range().end.row;
17063
17064                        if current_level < fold_at_level {
17065                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17066                        } else if current_level == fold_at_level {
17067                            to_fold.push(crease);
17068                        }
17069
17070                        start_row = nested_end_row + 1;
17071                    }
17072                    None => start_row += 1,
17073                }
17074            }
17075        }
17076
17077        self.fold_creases(to_fold, true, window, cx);
17078    }
17079
17080    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17081        if self.buffer.read(cx).is_singleton() {
17082            let mut fold_ranges = Vec::new();
17083            let snapshot = self.buffer.read(cx).snapshot(cx);
17084
17085            for row in 0..snapshot.max_row().0 {
17086                if let Some(foldable_range) = self
17087                    .snapshot(window, cx)
17088                    .crease_for_buffer_row(MultiBufferRow(row))
17089                {
17090                    fold_ranges.push(foldable_range);
17091                }
17092            }
17093
17094            self.fold_creases(fold_ranges, true, window, cx);
17095        } else {
17096            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17097                editor
17098                    .update_in(cx, |editor, _, cx| {
17099                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17100                            editor.fold_buffer(buffer_id, cx);
17101                        }
17102                    })
17103                    .ok();
17104            });
17105        }
17106    }
17107
17108    pub fn fold_function_bodies(
17109        &mut self,
17110        _: &actions::FoldFunctionBodies,
17111        window: &mut Window,
17112        cx: &mut Context<Self>,
17113    ) {
17114        let snapshot = self.buffer.read(cx).snapshot(cx);
17115
17116        let ranges = snapshot
17117            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17118            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17119            .collect::<Vec<_>>();
17120
17121        let creases = ranges
17122            .into_iter()
17123            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17124            .collect();
17125
17126        self.fold_creases(creases, true, window, cx);
17127    }
17128
17129    pub fn fold_recursive(
17130        &mut self,
17131        _: &actions::FoldRecursive,
17132        window: &mut Window,
17133        cx: &mut Context<Self>,
17134    ) {
17135        let mut to_fold = Vec::new();
17136        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17137        let selections = self.selections.all_adjusted(cx);
17138
17139        for selection in selections {
17140            let range = selection.range().sorted();
17141            let buffer_start_row = range.start.row;
17142
17143            if range.start.row != range.end.row {
17144                let mut found = false;
17145                for row in range.start.row..=range.end.row {
17146                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17147                        found = true;
17148                        to_fold.push(crease);
17149                    }
17150                }
17151                if found {
17152                    continue;
17153                }
17154            }
17155
17156            for row in (0..=range.start.row).rev() {
17157                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17158                    if crease.range().end.row >= buffer_start_row {
17159                        to_fold.push(crease);
17160                    } else {
17161                        break;
17162                    }
17163                }
17164            }
17165        }
17166
17167        self.fold_creases(to_fold, true, window, cx);
17168    }
17169
17170    pub fn fold_at(
17171        &mut self,
17172        buffer_row: MultiBufferRow,
17173        window: &mut Window,
17174        cx: &mut Context<Self>,
17175    ) {
17176        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17177
17178        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17179            let autoscroll = self
17180                .selections
17181                .all::<Point>(cx)
17182                .iter()
17183                .any(|selection| crease.range().overlaps(&selection.range()));
17184
17185            self.fold_creases(vec![crease], autoscroll, window, cx);
17186        }
17187    }
17188
17189    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17190        if self.is_singleton(cx) {
17191            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17192            let buffer = &display_map.buffer_snapshot;
17193            let selections = self.selections.all::<Point>(cx);
17194            let ranges = selections
17195                .iter()
17196                .map(|s| {
17197                    let range = s.display_range(&display_map).sorted();
17198                    let mut start = range.start.to_point(&display_map);
17199                    let mut end = range.end.to_point(&display_map);
17200                    start.column = 0;
17201                    end.column = buffer.line_len(MultiBufferRow(end.row));
17202                    start..end
17203                })
17204                .collect::<Vec<_>>();
17205
17206            self.unfold_ranges(&ranges, true, true, cx);
17207        } else {
17208            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17209            let buffer_ids = self
17210                .selections
17211                .disjoint_anchor_ranges()
17212                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17213                .collect::<HashSet<_>>();
17214            for buffer_id in buffer_ids {
17215                self.unfold_buffer(buffer_id, cx);
17216            }
17217        }
17218    }
17219
17220    pub fn unfold_recursive(
17221        &mut self,
17222        _: &UnfoldRecursive,
17223        _window: &mut Window,
17224        cx: &mut Context<Self>,
17225    ) {
17226        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17227        let selections = self.selections.all::<Point>(cx);
17228        let ranges = selections
17229            .iter()
17230            .map(|s| {
17231                let mut range = s.display_range(&display_map).sorted();
17232                *range.start.column_mut() = 0;
17233                *range.end.column_mut() = display_map.line_len(range.end.row());
17234                let start = range.start.to_point(&display_map);
17235                let end = range.end.to_point(&display_map);
17236                start..end
17237            })
17238            .collect::<Vec<_>>();
17239
17240        self.unfold_ranges(&ranges, true, true, cx);
17241    }
17242
17243    pub fn unfold_at(
17244        &mut self,
17245        buffer_row: MultiBufferRow,
17246        _window: &mut Window,
17247        cx: &mut Context<Self>,
17248    ) {
17249        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17250
17251        let intersection_range = Point::new(buffer_row.0, 0)
17252            ..Point::new(
17253                buffer_row.0,
17254                display_map.buffer_snapshot.line_len(buffer_row),
17255            );
17256
17257        let autoscroll = self
17258            .selections
17259            .all::<Point>(cx)
17260            .iter()
17261            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17262
17263        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17264    }
17265
17266    pub fn unfold_all(
17267        &mut self,
17268        _: &actions::UnfoldAll,
17269        _window: &mut Window,
17270        cx: &mut Context<Self>,
17271    ) {
17272        if self.buffer.read(cx).is_singleton() {
17273            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17274            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17275        } else {
17276            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17277                editor
17278                    .update(cx, |editor, cx| {
17279                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17280                            editor.unfold_buffer(buffer_id, cx);
17281                        }
17282                    })
17283                    .ok();
17284            });
17285        }
17286    }
17287
17288    pub fn fold_selected_ranges(
17289        &mut self,
17290        _: &FoldSelectedRanges,
17291        window: &mut Window,
17292        cx: &mut Context<Self>,
17293    ) {
17294        let selections = self.selections.all_adjusted(cx);
17295        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17296        let ranges = selections
17297            .into_iter()
17298            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17299            .collect::<Vec<_>>();
17300        self.fold_creases(ranges, true, window, cx);
17301    }
17302
17303    pub fn fold_ranges<T: ToOffset + Clone>(
17304        &mut self,
17305        ranges: Vec<Range<T>>,
17306        auto_scroll: bool,
17307        window: &mut Window,
17308        cx: &mut Context<Self>,
17309    ) {
17310        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17311        let ranges = ranges
17312            .into_iter()
17313            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17314            .collect::<Vec<_>>();
17315        self.fold_creases(ranges, auto_scroll, window, cx);
17316    }
17317
17318    pub fn fold_creases<T: ToOffset + Clone>(
17319        &mut self,
17320        creases: Vec<Crease<T>>,
17321        auto_scroll: bool,
17322        _window: &mut Window,
17323        cx: &mut Context<Self>,
17324    ) {
17325        if creases.is_empty() {
17326            return;
17327        }
17328
17329        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17330
17331        if auto_scroll {
17332            self.request_autoscroll(Autoscroll::fit(), cx);
17333        }
17334
17335        cx.notify();
17336
17337        self.scrollbar_marker_state.dirty = true;
17338        self.folds_did_change(cx);
17339    }
17340
17341    /// Removes any folds whose ranges intersect any of the given ranges.
17342    pub fn unfold_ranges<T: ToOffset + Clone>(
17343        &mut self,
17344        ranges: &[Range<T>],
17345        inclusive: bool,
17346        auto_scroll: bool,
17347        cx: &mut Context<Self>,
17348    ) {
17349        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17350            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17351        });
17352        self.folds_did_change(cx);
17353    }
17354
17355    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17356        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17357            return;
17358        }
17359        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17360        self.display_map.update(cx, |display_map, cx| {
17361            display_map.fold_buffers([buffer_id], cx)
17362        });
17363        cx.emit(EditorEvent::BufferFoldToggled {
17364            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17365            folded: true,
17366        });
17367        cx.notify();
17368    }
17369
17370    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17371        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17372            return;
17373        }
17374        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17375        self.display_map.update(cx, |display_map, cx| {
17376            display_map.unfold_buffers([buffer_id], cx);
17377        });
17378        cx.emit(EditorEvent::BufferFoldToggled {
17379            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17380            folded: false,
17381        });
17382        cx.notify();
17383    }
17384
17385    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17386        self.display_map.read(cx).is_buffer_folded(buffer)
17387    }
17388
17389    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17390        self.display_map.read(cx).folded_buffers()
17391    }
17392
17393    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17394        self.display_map.update(cx, |display_map, cx| {
17395            display_map.disable_header_for_buffer(buffer_id, cx);
17396        });
17397        cx.notify();
17398    }
17399
17400    /// Removes any folds with the given ranges.
17401    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17402        &mut self,
17403        ranges: &[Range<T>],
17404        type_id: TypeId,
17405        auto_scroll: bool,
17406        cx: &mut Context<Self>,
17407    ) {
17408        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17409            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17410        });
17411        self.folds_did_change(cx);
17412    }
17413
17414    fn remove_folds_with<T: ToOffset + Clone>(
17415        &mut self,
17416        ranges: &[Range<T>],
17417        auto_scroll: bool,
17418        cx: &mut Context<Self>,
17419        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17420    ) {
17421        if ranges.is_empty() {
17422            return;
17423        }
17424
17425        let mut buffers_affected = HashSet::default();
17426        let multi_buffer = self.buffer().read(cx);
17427        for range in ranges {
17428            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17429                buffers_affected.insert(buffer.read(cx).remote_id());
17430            };
17431        }
17432
17433        self.display_map.update(cx, update);
17434
17435        if auto_scroll {
17436            self.request_autoscroll(Autoscroll::fit(), cx);
17437        }
17438
17439        cx.notify();
17440        self.scrollbar_marker_state.dirty = true;
17441        self.active_indent_guides_state.dirty = true;
17442    }
17443
17444    pub fn update_renderer_widths(
17445        &mut self,
17446        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17447        cx: &mut Context<Self>,
17448    ) -> bool {
17449        self.display_map
17450            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17451    }
17452
17453    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17454        self.display_map.read(cx).fold_placeholder.clone()
17455    }
17456
17457    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17458        self.buffer.update(cx, |buffer, cx| {
17459            buffer.set_all_diff_hunks_expanded(cx);
17460        });
17461    }
17462
17463    pub fn expand_all_diff_hunks(
17464        &mut self,
17465        _: &ExpandAllDiffHunks,
17466        _window: &mut Window,
17467        cx: &mut Context<Self>,
17468    ) {
17469        self.buffer.update(cx, |buffer, cx| {
17470            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17471        });
17472    }
17473
17474    pub fn toggle_selected_diff_hunks(
17475        &mut self,
17476        _: &ToggleSelectedDiffHunks,
17477        _window: &mut Window,
17478        cx: &mut Context<Self>,
17479    ) {
17480        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17481        self.toggle_diff_hunks_in_ranges(ranges, cx);
17482    }
17483
17484    pub fn diff_hunks_in_ranges<'a>(
17485        &'a self,
17486        ranges: &'a [Range<Anchor>],
17487        buffer: &'a MultiBufferSnapshot,
17488    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17489        ranges.iter().flat_map(move |range| {
17490            let end_excerpt_id = range.end.excerpt_id;
17491            let range = range.to_point(buffer);
17492            let mut peek_end = range.end;
17493            if range.end.row < buffer.max_row().0 {
17494                peek_end = Point::new(range.end.row + 1, 0);
17495            }
17496            buffer
17497                .diff_hunks_in_range(range.start..peek_end)
17498                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17499        })
17500    }
17501
17502    pub fn has_stageable_diff_hunks_in_ranges(
17503        &self,
17504        ranges: &[Range<Anchor>],
17505        snapshot: &MultiBufferSnapshot,
17506    ) -> bool {
17507        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17508        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17509    }
17510
17511    pub fn toggle_staged_selected_diff_hunks(
17512        &mut self,
17513        _: &::git::ToggleStaged,
17514        _: &mut Window,
17515        cx: &mut Context<Self>,
17516    ) {
17517        let snapshot = self.buffer.read(cx).snapshot(cx);
17518        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17519        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17520        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17521    }
17522
17523    pub fn set_render_diff_hunk_controls(
17524        &mut self,
17525        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17526        cx: &mut Context<Self>,
17527    ) {
17528        self.render_diff_hunk_controls = render_diff_hunk_controls;
17529        cx.notify();
17530    }
17531
17532    pub fn stage_and_next(
17533        &mut self,
17534        _: &::git::StageAndNext,
17535        window: &mut Window,
17536        cx: &mut Context<Self>,
17537    ) {
17538        self.do_stage_or_unstage_and_next(true, window, cx);
17539    }
17540
17541    pub fn unstage_and_next(
17542        &mut self,
17543        _: &::git::UnstageAndNext,
17544        window: &mut Window,
17545        cx: &mut Context<Self>,
17546    ) {
17547        self.do_stage_or_unstage_and_next(false, window, cx);
17548    }
17549
17550    pub fn stage_or_unstage_diff_hunks(
17551        &mut self,
17552        stage: bool,
17553        ranges: Vec<Range<Anchor>>,
17554        cx: &mut Context<Self>,
17555    ) {
17556        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17557        cx.spawn(async move |this, cx| {
17558            task.await?;
17559            this.update(cx, |this, cx| {
17560                let snapshot = this.buffer.read(cx).snapshot(cx);
17561                let chunk_by = this
17562                    .diff_hunks_in_ranges(&ranges, &snapshot)
17563                    .chunk_by(|hunk| hunk.buffer_id);
17564                for (buffer_id, hunks) in &chunk_by {
17565                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17566                }
17567            })
17568        })
17569        .detach_and_log_err(cx);
17570    }
17571
17572    fn save_buffers_for_ranges_if_needed(
17573        &mut self,
17574        ranges: &[Range<Anchor>],
17575        cx: &mut Context<Editor>,
17576    ) -> Task<Result<()>> {
17577        let multibuffer = self.buffer.read(cx);
17578        let snapshot = multibuffer.read(cx);
17579        let buffer_ids: HashSet<_> = ranges
17580            .iter()
17581            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17582            .collect();
17583        drop(snapshot);
17584
17585        let mut buffers = HashSet::default();
17586        for buffer_id in buffer_ids {
17587            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17588                let buffer = buffer_entity.read(cx);
17589                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17590                {
17591                    buffers.insert(buffer_entity);
17592                }
17593            }
17594        }
17595
17596        if let Some(project) = &self.project {
17597            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17598        } else {
17599            Task::ready(Ok(()))
17600        }
17601    }
17602
17603    fn do_stage_or_unstage_and_next(
17604        &mut self,
17605        stage: bool,
17606        window: &mut Window,
17607        cx: &mut Context<Self>,
17608    ) {
17609        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17610
17611        if ranges.iter().any(|range| range.start != range.end) {
17612            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17613            return;
17614        }
17615
17616        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17617        let snapshot = self.snapshot(window, cx);
17618        let position = self.selections.newest::<Point>(cx).head();
17619        let mut row = snapshot
17620            .buffer_snapshot
17621            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17622            .find(|hunk| hunk.row_range.start.0 > position.row)
17623            .map(|hunk| hunk.row_range.start);
17624
17625        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17626        // Outside of the project diff editor, wrap around to the beginning.
17627        if !all_diff_hunks_expanded {
17628            row = row.or_else(|| {
17629                snapshot
17630                    .buffer_snapshot
17631                    .diff_hunks_in_range(Point::zero()..position)
17632                    .find(|hunk| hunk.row_range.end.0 < position.row)
17633                    .map(|hunk| hunk.row_range.start)
17634            });
17635        }
17636
17637        if let Some(row) = row {
17638            let destination = Point::new(row.0, 0);
17639            let autoscroll = Autoscroll::center();
17640
17641            self.unfold_ranges(&[destination..destination], false, false, cx);
17642            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17643                s.select_ranges([destination..destination]);
17644            });
17645        }
17646    }
17647
17648    fn do_stage_or_unstage(
17649        &self,
17650        stage: bool,
17651        buffer_id: BufferId,
17652        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17653        cx: &mut App,
17654    ) -> Option<()> {
17655        let project = self.project.as_ref()?;
17656        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17657        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17658        let buffer_snapshot = buffer.read(cx).snapshot();
17659        let file_exists = buffer_snapshot
17660            .file()
17661            .is_some_and(|file| file.disk_state().exists());
17662        diff.update(cx, |diff, cx| {
17663            diff.stage_or_unstage_hunks(
17664                stage,
17665                &hunks
17666                    .map(|hunk| buffer_diff::DiffHunk {
17667                        buffer_range: hunk.buffer_range,
17668                        diff_base_byte_range: hunk.diff_base_byte_range,
17669                        secondary_status: hunk.secondary_status,
17670                        range: Point::zero()..Point::zero(), // unused
17671                    })
17672                    .collect::<Vec<_>>(),
17673                &buffer_snapshot,
17674                file_exists,
17675                cx,
17676            )
17677        });
17678        None
17679    }
17680
17681    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17682        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17683        self.buffer
17684            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17685    }
17686
17687    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17688        self.buffer.update(cx, |buffer, cx| {
17689            let ranges = vec![Anchor::min()..Anchor::max()];
17690            if !buffer.all_diff_hunks_expanded()
17691                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17692            {
17693                buffer.collapse_diff_hunks(ranges, cx);
17694                true
17695            } else {
17696                false
17697            }
17698        })
17699    }
17700
17701    fn toggle_diff_hunks_in_ranges(
17702        &mut self,
17703        ranges: Vec<Range<Anchor>>,
17704        cx: &mut Context<Editor>,
17705    ) {
17706        self.buffer.update(cx, |buffer, cx| {
17707            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17708            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17709        })
17710    }
17711
17712    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17713        self.buffer.update(cx, |buffer, cx| {
17714            let snapshot = buffer.snapshot(cx);
17715            let excerpt_id = range.end.excerpt_id;
17716            let point_range = range.to_point(&snapshot);
17717            let expand = !buffer.single_hunk_is_expanded(range, cx);
17718            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17719        })
17720    }
17721
17722    pub(crate) fn apply_all_diff_hunks(
17723        &mut self,
17724        _: &ApplyAllDiffHunks,
17725        window: &mut Window,
17726        cx: &mut Context<Self>,
17727    ) {
17728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17729
17730        let buffers = self.buffer.read(cx).all_buffers();
17731        for branch_buffer in buffers {
17732            branch_buffer.update(cx, |branch_buffer, cx| {
17733                branch_buffer.merge_into_base(Vec::new(), cx);
17734            });
17735        }
17736
17737        if let Some(project) = self.project.clone() {
17738            self.save(
17739                SaveOptions {
17740                    format: true,
17741                    autosave: false,
17742                },
17743                project,
17744                window,
17745                cx,
17746            )
17747            .detach_and_log_err(cx);
17748        }
17749    }
17750
17751    pub(crate) fn apply_selected_diff_hunks(
17752        &mut self,
17753        _: &ApplyDiffHunk,
17754        window: &mut Window,
17755        cx: &mut Context<Self>,
17756    ) {
17757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17758        let snapshot = self.snapshot(window, cx);
17759        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17760        let mut ranges_by_buffer = HashMap::default();
17761        self.transact(window, cx, |editor, _window, cx| {
17762            for hunk in hunks {
17763                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17764                    ranges_by_buffer
17765                        .entry(buffer.clone())
17766                        .or_insert_with(Vec::new)
17767                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17768                }
17769            }
17770
17771            for (buffer, ranges) in ranges_by_buffer {
17772                buffer.update(cx, |buffer, cx| {
17773                    buffer.merge_into_base(ranges, cx);
17774                });
17775            }
17776        });
17777
17778        if let Some(project) = self.project.clone() {
17779            self.save(
17780                SaveOptions {
17781                    format: true,
17782                    autosave: false,
17783                },
17784                project,
17785                window,
17786                cx,
17787            )
17788            .detach_and_log_err(cx);
17789        }
17790    }
17791
17792    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17793        if hovered != self.gutter_hovered {
17794            self.gutter_hovered = hovered;
17795            cx.notify();
17796        }
17797    }
17798
17799    pub fn insert_blocks(
17800        &mut self,
17801        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17802        autoscroll: Option<Autoscroll>,
17803        cx: &mut Context<Self>,
17804    ) -> Vec<CustomBlockId> {
17805        let blocks = self
17806            .display_map
17807            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17808        if let Some(autoscroll) = autoscroll {
17809            self.request_autoscroll(autoscroll, cx);
17810        }
17811        cx.notify();
17812        blocks
17813    }
17814
17815    pub fn resize_blocks(
17816        &mut self,
17817        heights: HashMap<CustomBlockId, u32>,
17818        autoscroll: Option<Autoscroll>,
17819        cx: &mut Context<Self>,
17820    ) {
17821        self.display_map
17822            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17823        if let Some(autoscroll) = autoscroll {
17824            self.request_autoscroll(autoscroll, cx);
17825        }
17826        cx.notify();
17827    }
17828
17829    pub fn replace_blocks(
17830        &mut self,
17831        renderers: HashMap<CustomBlockId, RenderBlock>,
17832        autoscroll: Option<Autoscroll>,
17833        cx: &mut Context<Self>,
17834    ) {
17835        self.display_map
17836            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17837        if let Some(autoscroll) = autoscroll {
17838            self.request_autoscroll(autoscroll, cx);
17839        }
17840        cx.notify();
17841    }
17842
17843    pub fn remove_blocks(
17844        &mut self,
17845        block_ids: HashSet<CustomBlockId>,
17846        autoscroll: Option<Autoscroll>,
17847        cx: &mut Context<Self>,
17848    ) {
17849        self.display_map.update(cx, |display_map, cx| {
17850            display_map.remove_blocks(block_ids, cx)
17851        });
17852        if let Some(autoscroll) = autoscroll {
17853            self.request_autoscroll(autoscroll, cx);
17854        }
17855        cx.notify();
17856    }
17857
17858    pub fn row_for_block(
17859        &self,
17860        block_id: CustomBlockId,
17861        cx: &mut Context<Self>,
17862    ) -> Option<DisplayRow> {
17863        self.display_map
17864            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17865    }
17866
17867    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17868        self.focused_block = Some(focused_block);
17869    }
17870
17871    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17872        self.focused_block.take()
17873    }
17874
17875    pub fn insert_creases(
17876        &mut self,
17877        creases: impl IntoIterator<Item = Crease<Anchor>>,
17878        cx: &mut Context<Self>,
17879    ) -> Vec<CreaseId> {
17880        self.display_map
17881            .update(cx, |map, cx| map.insert_creases(creases, cx))
17882    }
17883
17884    pub fn remove_creases(
17885        &mut self,
17886        ids: impl IntoIterator<Item = CreaseId>,
17887        cx: &mut Context<Self>,
17888    ) -> Vec<(CreaseId, Range<Anchor>)> {
17889        self.display_map
17890            .update(cx, |map, cx| map.remove_creases(ids, cx))
17891    }
17892
17893    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17894        self.display_map
17895            .update(cx, |map, cx| map.snapshot(cx))
17896            .longest_row()
17897    }
17898
17899    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17900        self.display_map
17901            .update(cx, |map, cx| map.snapshot(cx))
17902            .max_point()
17903    }
17904
17905    pub fn text(&self, cx: &App) -> String {
17906        self.buffer.read(cx).read(cx).text()
17907    }
17908
17909    pub fn is_empty(&self, cx: &App) -> bool {
17910        self.buffer.read(cx).read(cx).is_empty()
17911    }
17912
17913    pub fn text_option(&self, cx: &App) -> Option<String> {
17914        let text = self.text(cx);
17915        let text = text.trim();
17916
17917        if text.is_empty() {
17918            return None;
17919        }
17920
17921        Some(text.to_string())
17922    }
17923
17924    pub fn set_text(
17925        &mut self,
17926        text: impl Into<Arc<str>>,
17927        window: &mut Window,
17928        cx: &mut Context<Self>,
17929    ) {
17930        self.transact(window, cx, |this, _, cx| {
17931            this.buffer
17932                .read(cx)
17933                .as_singleton()
17934                .expect("you can only call set_text on editors for singleton buffers")
17935                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17936        });
17937    }
17938
17939    pub fn display_text(&self, cx: &mut App) -> String {
17940        self.display_map
17941            .update(cx, |map, cx| map.snapshot(cx))
17942            .text()
17943    }
17944
17945    fn create_minimap(
17946        &self,
17947        minimap_settings: MinimapSettings,
17948        window: &mut Window,
17949        cx: &mut Context<Self>,
17950    ) -> Option<Entity<Self>> {
17951        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17952            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17953    }
17954
17955    fn initialize_new_minimap(
17956        &self,
17957        minimap_settings: MinimapSettings,
17958        window: &mut Window,
17959        cx: &mut Context<Self>,
17960    ) -> Entity<Self> {
17961        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17962
17963        let mut minimap = Editor::new_internal(
17964            EditorMode::Minimap {
17965                parent: cx.weak_entity(),
17966            },
17967            self.buffer.clone(),
17968            self.project.clone(),
17969            Some(self.display_map.clone()),
17970            window,
17971            cx,
17972        );
17973        minimap.scroll_manager.clone_state(&self.scroll_manager);
17974        minimap.set_text_style_refinement(TextStyleRefinement {
17975            font_size: Some(MINIMAP_FONT_SIZE),
17976            font_weight: Some(MINIMAP_FONT_WEIGHT),
17977            ..Default::default()
17978        });
17979        minimap.update_minimap_configuration(minimap_settings, cx);
17980        cx.new(|_| minimap)
17981    }
17982
17983    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17984        let current_line_highlight = minimap_settings
17985            .current_line_highlight
17986            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17987        self.set_current_line_highlight(Some(current_line_highlight));
17988    }
17989
17990    pub fn minimap(&self) -> Option<&Entity<Self>> {
17991        self.minimap
17992            .as_ref()
17993            .filter(|_| self.minimap_visibility.visible())
17994    }
17995
17996    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17997        let mut wrap_guides = smallvec![];
17998
17999        if self.show_wrap_guides == Some(false) {
18000            return wrap_guides;
18001        }
18002
18003        let settings = self.buffer.read(cx).language_settings(cx);
18004        if settings.show_wrap_guides {
18005            match self.soft_wrap_mode(cx) {
18006                SoftWrap::Column(soft_wrap) => {
18007                    wrap_guides.push((soft_wrap as usize, true));
18008                }
18009                SoftWrap::Bounded(soft_wrap) => {
18010                    wrap_guides.push((soft_wrap as usize, true));
18011                }
18012                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18013            }
18014            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18015        }
18016
18017        wrap_guides
18018    }
18019
18020    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18021        let settings = self.buffer.read(cx).language_settings(cx);
18022        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18023        match mode {
18024            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18025                SoftWrap::None
18026            }
18027            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18028            language_settings::SoftWrap::PreferredLineLength => {
18029                SoftWrap::Column(settings.preferred_line_length)
18030            }
18031            language_settings::SoftWrap::Bounded => {
18032                SoftWrap::Bounded(settings.preferred_line_length)
18033            }
18034        }
18035    }
18036
18037    pub fn set_soft_wrap_mode(
18038        &mut self,
18039        mode: language_settings::SoftWrap,
18040
18041        cx: &mut Context<Self>,
18042    ) {
18043        self.soft_wrap_mode_override = Some(mode);
18044        cx.notify();
18045    }
18046
18047    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18048        self.hard_wrap = hard_wrap;
18049        cx.notify();
18050    }
18051
18052    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18053        self.text_style_refinement = Some(style);
18054    }
18055
18056    /// called by the Element so we know what style we were most recently rendered with.
18057    pub(crate) fn set_style(
18058        &mut self,
18059        style: EditorStyle,
18060        window: &mut Window,
18061        cx: &mut Context<Self>,
18062    ) {
18063        // We intentionally do not inform the display map about the minimap style
18064        // so that wrapping is not recalculated and stays consistent for the editor
18065        // and its linked minimap.
18066        if !self.mode.is_minimap() {
18067            let rem_size = window.rem_size();
18068            self.display_map.update(cx, |map, cx| {
18069                map.set_font(
18070                    style.text.font(),
18071                    style.text.font_size.to_pixels(rem_size),
18072                    cx,
18073                )
18074            });
18075        }
18076        self.style = Some(style);
18077    }
18078
18079    pub fn style(&self) -> Option<&EditorStyle> {
18080        self.style.as_ref()
18081    }
18082
18083    // Called by the element. This method is not designed to be called outside of the editor
18084    // element's layout code because it does not notify when rewrapping is computed synchronously.
18085    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18086        self.display_map
18087            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18088    }
18089
18090    pub fn set_soft_wrap(&mut self) {
18091        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18092    }
18093
18094    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18095        if self.soft_wrap_mode_override.is_some() {
18096            self.soft_wrap_mode_override.take();
18097        } else {
18098            let soft_wrap = match self.soft_wrap_mode(cx) {
18099                SoftWrap::GitDiff => return,
18100                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18101                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18102                    language_settings::SoftWrap::None
18103                }
18104            };
18105            self.soft_wrap_mode_override = Some(soft_wrap);
18106        }
18107        cx.notify();
18108    }
18109
18110    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18111        let Some(workspace) = self.workspace() else {
18112            return;
18113        };
18114        let fs = workspace.read(cx).app_state().fs.clone();
18115        let current_show = TabBarSettings::get_global(cx).show;
18116        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18117            setting.show = Some(!current_show);
18118        });
18119    }
18120
18121    pub fn toggle_indent_guides(
18122        &mut self,
18123        _: &ToggleIndentGuides,
18124        _: &mut Window,
18125        cx: &mut Context<Self>,
18126    ) {
18127        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18128            self.buffer
18129                .read(cx)
18130                .language_settings(cx)
18131                .indent_guides
18132                .enabled
18133        });
18134        self.show_indent_guides = Some(!currently_enabled);
18135        cx.notify();
18136    }
18137
18138    fn should_show_indent_guides(&self) -> Option<bool> {
18139        self.show_indent_guides
18140    }
18141
18142    pub fn toggle_line_numbers(
18143        &mut self,
18144        _: &ToggleLineNumbers,
18145        _: &mut Window,
18146        cx: &mut Context<Self>,
18147    ) {
18148        let mut editor_settings = EditorSettings::get_global(cx).clone();
18149        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18150        EditorSettings::override_global(editor_settings, cx);
18151    }
18152
18153    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18154        if let Some(show_line_numbers) = self.show_line_numbers {
18155            return show_line_numbers;
18156        }
18157        EditorSettings::get_global(cx).gutter.line_numbers
18158    }
18159
18160    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18161        self.use_relative_line_numbers
18162            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18163    }
18164
18165    pub fn toggle_relative_line_numbers(
18166        &mut self,
18167        _: &ToggleRelativeLineNumbers,
18168        _: &mut Window,
18169        cx: &mut Context<Self>,
18170    ) {
18171        let is_relative = self.should_use_relative_line_numbers(cx);
18172        self.set_relative_line_number(Some(!is_relative), cx)
18173    }
18174
18175    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18176        self.use_relative_line_numbers = is_relative;
18177        cx.notify();
18178    }
18179
18180    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18181        self.show_gutter = show_gutter;
18182        cx.notify();
18183    }
18184
18185    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18186        self.show_scrollbars = ScrollbarAxes {
18187            horizontal: show,
18188            vertical: show,
18189        };
18190        cx.notify();
18191    }
18192
18193    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18194        self.show_scrollbars.vertical = show;
18195        cx.notify();
18196    }
18197
18198    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18199        self.show_scrollbars.horizontal = show;
18200        cx.notify();
18201    }
18202
18203    pub fn set_minimap_visibility(
18204        &mut self,
18205        minimap_visibility: MinimapVisibility,
18206        window: &mut Window,
18207        cx: &mut Context<Self>,
18208    ) {
18209        if self.minimap_visibility != minimap_visibility {
18210            if minimap_visibility.visible() && self.minimap.is_none() {
18211                let minimap_settings = EditorSettings::get_global(cx).minimap;
18212                self.minimap =
18213                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18214            }
18215            self.minimap_visibility = minimap_visibility;
18216            cx.notify();
18217        }
18218    }
18219
18220    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18221        self.set_show_scrollbars(false, cx);
18222        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18223    }
18224
18225    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18226        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18227    }
18228
18229    /// Normally the text in full mode and auto height editors is padded on the
18230    /// left side by roughly half a character width for improved hit testing.
18231    ///
18232    /// Use this method to disable this for cases where this is not wanted (e.g.
18233    /// if you want to align the editor text with some other text above or below)
18234    /// or if you want to add this padding to single-line editors.
18235    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18236        self.offset_content = offset_content;
18237        cx.notify();
18238    }
18239
18240    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18241        self.show_line_numbers = Some(show_line_numbers);
18242        cx.notify();
18243    }
18244
18245    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18246        self.disable_expand_excerpt_buttons = true;
18247        cx.notify();
18248    }
18249
18250    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18251        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18252        cx.notify();
18253    }
18254
18255    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18256        self.show_code_actions = Some(show_code_actions);
18257        cx.notify();
18258    }
18259
18260    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18261        self.show_runnables = Some(show_runnables);
18262        cx.notify();
18263    }
18264
18265    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18266        self.show_breakpoints = Some(show_breakpoints);
18267        cx.notify();
18268    }
18269
18270    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18271        if self.display_map.read(cx).masked != masked {
18272            self.display_map.update(cx, |map, _| map.masked = masked);
18273        }
18274        cx.notify()
18275    }
18276
18277    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18278        self.show_wrap_guides = Some(show_wrap_guides);
18279        cx.notify();
18280    }
18281
18282    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18283        self.show_indent_guides = Some(show_indent_guides);
18284        cx.notify();
18285    }
18286
18287    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18288        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18289            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18290                if let Some(dir) = file.abs_path(cx).parent() {
18291                    return Some(dir.to_owned());
18292                }
18293            }
18294
18295            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18296                return Some(project_path.path.to_path_buf());
18297            }
18298        }
18299
18300        None
18301    }
18302
18303    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18304        self.active_excerpt(cx)?
18305            .1
18306            .read(cx)
18307            .file()
18308            .and_then(|f| f.as_local())
18309    }
18310
18311    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18312        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18313            let buffer = buffer.read(cx);
18314            if let Some(project_path) = buffer.project_path(cx) {
18315                let project = self.project.as_ref()?.read(cx);
18316                project.absolute_path(&project_path, cx)
18317            } else {
18318                buffer
18319                    .file()
18320                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18321            }
18322        })
18323    }
18324
18325    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18326        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18327            let project_path = buffer.read(cx).project_path(cx)?;
18328            let project = self.project.as_ref()?.read(cx);
18329            let entry = project.entry_for_path(&project_path, cx)?;
18330            let path = entry.path.to_path_buf();
18331            Some(path)
18332        })
18333    }
18334
18335    pub fn reveal_in_finder(
18336        &mut self,
18337        _: &RevealInFileManager,
18338        _window: &mut Window,
18339        cx: &mut Context<Self>,
18340    ) {
18341        if let Some(target) = self.target_file(cx) {
18342            cx.reveal_path(&target.abs_path(cx));
18343        }
18344    }
18345
18346    pub fn copy_path(
18347        &mut self,
18348        _: &zed_actions::workspace::CopyPath,
18349        _window: &mut Window,
18350        cx: &mut Context<Self>,
18351    ) {
18352        if let Some(path) = self.target_file_abs_path(cx) {
18353            if let Some(path) = path.to_str() {
18354                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18355            }
18356        }
18357    }
18358
18359    pub fn copy_relative_path(
18360        &mut self,
18361        _: &zed_actions::workspace::CopyRelativePath,
18362        _window: &mut Window,
18363        cx: &mut Context<Self>,
18364    ) {
18365        if let Some(path) = self.target_file_path(cx) {
18366            if let Some(path) = path.to_str() {
18367                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18368            }
18369        }
18370    }
18371
18372    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18373        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18374            buffer.read(cx).project_path(cx)
18375        } else {
18376            None
18377        }
18378    }
18379
18380    // Returns true if the editor handled a go-to-line request
18381    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18382        maybe!({
18383            let breakpoint_store = self.breakpoint_store.as_ref()?;
18384
18385            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18386            else {
18387                self.clear_row_highlights::<ActiveDebugLine>();
18388                return None;
18389            };
18390
18391            let position = active_stack_frame.position;
18392            let buffer_id = position.buffer_id?;
18393            let snapshot = self
18394                .project
18395                .as_ref()?
18396                .read(cx)
18397                .buffer_for_id(buffer_id, cx)?
18398                .read(cx)
18399                .snapshot();
18400
18401            let mut handled = false;
18402            for (id, ExcerptRange { context, .. }) in
18403                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18404            {
18405                if context.start.cmp(&position, &snapshot).is_ge()
18406                    || context.end.cmp(&position, &snapshot).is_lt()
18407                {
18408                    continue;
18409                }
18410                let snapshot = self.buffer.read(cx).snapshot(cx);
18411                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18412
18413                handled = true;
18414                self.clear_row_highlights::<ActiveDebugLine>();
18415
18416                self.go_to_line::<ActiveDebugLine>(
18417                    multibuffer_anchor,
18418                    Some(cx.theme().colors().editor_debugger_active_line_background),
18419                    window,
18420                    cx,
18421                );
18422
18423                cx.notify();
18424            }
18425
18426            handled.then_some(())
18427        })
18428        .is_some()
18429    }
18430
18431    pub fn copy_file_name_without_extension(
18432        &mut self,
18433        _: &CopyFileNameWithoutExtension,
18434        _: &mut Window,
18435        cx: &mut Context<Self>,
18436    ) {
18437        if let Some(file) = self.target_file(cx) {
18438            if let Some(file_stem) = file.path().file_stem() {
18439                if let Some(name) = file_stem.to_str() {
18440                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18441                }
18442            }
18443        }
18444    }
18445
18446    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18447        if let Some(file) = self.target_file(cx) {
18448            if let Some(file_name) = file.path().file_name() {
18449                if let Some(name) = file_name.to_str() {
18450                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18451                }
18452            }
18453        }
18454    }
18455
18456    pub fn toggle_git_blame(
18457        &mut self,
18458        _: &::git::Blame,
18459        window: &mut Window,
18460        cx: &mut Context<Self>,
18461    ) {
18462        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18463
18464        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18465            self.start_git_blame(true, window, cx);
18466        }
18467
18468        cx.notify();
18469    }
18470
18471    pub fn toggle_git_blame_inline(
18472        &mut self,
18473        _: &ToggleGitBlameInline,
18474        window: &mut Window,
18475        cx: &mut Context<Self>,
18476    ) {
18477        self.toggle_git_blame_inline_internal(true, window, cx);
18478        cx.notify();
18479    }
18480
18481    pub fn open_git_blame_commit(
18482        &mut self,
18483        _: &OpenGitBlameCommit,
18484        window: &mut Window,
18485        cx: &mut Context<Self>,
18486    ) {
18487        self.open_git_blame_commit_internal(window, cx);
18488    }
18489
18490    fn open_git_blame_commit_internal(
18491        &mut self,
18492        window: &mut Window,
18493        cx: &mut Context<Self>,
18494    ) -> Option<()> {
18495        let blame = self.blame.as_ref()?;
18496        let snapshot = self.snapshot(window, cx);
18497        let cursor = self.selections.newest::<Point>(cx).head();
18498        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18499        let blame_entry = blame
18500            .update(cx, |blame, cx| {
18501                blame
18502                    .blame_for_rows(
18503                        &[RowInfo {
18504                            buffer_id: Some(buffer.remote_id()),
18505                            buffer_row: Some(point.row),
18506                            ..Default::default()
18507                        }],
18508                        cx,
18509                    )
18510                    .next()
18511            })
18512            .flatten()?;
18513        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18514        let repo = blame.read(cx).repository(cx)?;
18515        let workspace = self.workspace()?.downgrade();
18516        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18517        None
18518    }
18519
18520    pub fn git_blame_inline_enabled(&self) -> bool {
18521        self.git_blame_inline_enabled
18522    }
18523
18524    pub fn toggle_selection_menu(
18525        &mut self,
18526        _: &ToggleSelectionMenu,
18527        _: &mut Window,
18528        cx: &mut Context<Self>,
18529    ) {
18530        self.show_selection_menu = self
18531            .show_selection_menu
18532            .map(|show_selections_menu| !show_selections_menu)
18533            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18534
18535        cx.notify();
18536    }
18537
18538    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18539        self.show_selection_menu
18540            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18541    }
18542
18543    fn start_git_blame(
18544        &mut self,
18545        user_triggered: bool,
18546        window: &mut Window,
18547        cx: &mut Context<Self>,
18548    ) {
18549        if let Some(project) = self.project.as_ref() {
18550            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18551                return;
18552            };
18553
18554            if buffer.read(cx).file().is_none() {
18555                return;
18556            }
18557
18558            let focused = self.focus_handle(cx).contains_focused(window, cx);
18559
18560            let project = project.clone();
18561            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18562            self.blame_subscription =
18563                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18564            self.blame = Some(blame);
18565        }
18566    }
18567
18568    fn toggle_git_blame_inline_internal(
18569        &mut self,
18570        user_triggered: bool,
18571        window: &mut Window,
18572        cx: &mut Context<Self>,
18573    ) {
18574        if self.git_blame_inline_enabled {
18575            self.git_blame_inline_enabled = false;
18576            self.show_git_blame_inline = false;
18577            self.show_git_blame_inline_delay_task.take();
18578        } else {
18579            self.git_blame_inline_enabled = true;
18580            self.start_git_blame_inline(user_triggered, window, cx);
18581        }
18582
18583        cx.notify();
18584    }
18585
18586    fn start_git_blame_inline(
18587        &mut self,
18588        user_triggered: bool,
18589        window: &mut Window,
18590        cx: &mut Context<Self>,
18591    ) {
18592        self.start_git_blame(user_triggered, window, cx);
18593
18594        if ProjectSettings::get_global(cx)
18595            .git
18596            .inline_blame_delay()
18597            .is_some()
18598        {
18599            self.start_inline_blame_timer(window, cx);
18600        } else {
18601            self.show_git_blame_inline = true
18602        }
18603    }
18604
18605    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18606        self.blame.as_ref()
18607    }
18608
18609    pub fn show_git_blame_gutter(&self) -> bool {
18610        self.show_git_blame_gutter
18611    }
18612
18613    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18614        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18615    }
18616
18617    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18618        self.show_git_blame_inline
18619            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18620            && !self.newest_selection_head_on_empty_line(cx)
18621            && self.has_blame_entries(cx)
18622    }
18623
18624    fn has_blame_entries(&self, cx: &App) -> bool {
18625        self.blame()
18626            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18627    }
18628
18629    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18630        let cursor_anchor = self.selections.newest_anchor().head();
18631
18632        let snapshot = self.buffer.read(cx).snapshot(cx);
18633        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18634
18635        snapshot.line_len(buffer_row) == 0
18636    }
18637
18638    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18639        let buffer_and_selection = maybe!({
18640            let selection = self.selections.newest::<Point>(cx);
18641            let selection_range = selection.range();
18642
18643            let multi_buffer = self.buffer().read(cx);
18644            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18645            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18646
18647            let (buffer, range, _) = if selection.reversed {
18648                buffer_ranges.first()
18649            } else {
18650                buffer_ranges.last()
18651            }?;
18652
18653            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18654                ..text::ToPoint::to_point(&range.end, &buffer).row;
18655            Some((
18656                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18657                selection,
18658            ))
18659        });
18660
18661        let Some((buffer, selection)) = buffer_and_selection else {
18662            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18663        };
18664
18665        let Some(project) = self.project.as_ref() else {
18666            return Task::ready(Err(anyhow!("editor does not have project")));
18667        };
18668
18669        project.update(cx, |project, cx| {
18670            project.get_permalink_to_line(&buffer, selection, cx)
18671        })
18672    }
18673
18674    pub fn copy_permalink_to_line(
18675        &mut self,
18676        _: &CopyPermalinkToLine,
18677        window: &mut Window,
18678        cx: &mut Context<Self>,
18679    ) {
18680        let permalink_task = self.get_permalink_to_line(cx);
18681        let workspace = self.workspace();
18682
18683        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18684            Ok(permalink) => {
18685                cx.update(|_, cx| {
18686                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18687                })
18688                .ok();
18689            }
18690            Err(err) => {
18691                let message = format!("Failed to copy permalink: {err}");
18692
18693                anyhow::Result::<()>::Err(err).log_err();
18694
18695                if let Some(workspace) = workspace {
18696                    workspace
18697                        .update_in(cx, |workspace, _, cx| {
18698                            struct CopyPermalinkToLine;
18699
18700                            workspace.show_toast(
18701                                Toast::new(
18702                                    NotificationId::unique::<CopyPermalinkToLine>(),
18703                                    message,
18704                                ),
18705                                cx,
18706                            )
18707                        })
18708                        .ok();
18709                }
18710            }
18711        })
18712        .detach();
18713    }
18714
18715    pub fn copy_file_location(
18716        &mut self,
18717        _: &CopyFileLocation,
18718        _: &mut Window,
18719        cx: &mut Context<Self>,
18720    ) {
18721        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18722        if let Some(file) = self.target_file(cx) {
18723            if let Some(path) = file.path().to_str() {
18724                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18725            }
18726        }
18727    }
18728
18729    pub fn open_permalink_to_line(
18730        &mut self,
18731        _: &OpenPermalinkToLine,
18732        window: &mut Window,
18733        cx: &mut Context<Self>,
18734    ) {
18735        let permalink_task = self.get_permalink_to_line(cx);
18736        let workspace = self.workspace();
18737
18738        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18739            Ok(permalink) => {
18740                cx.update(|_, cx| {
18741                    cx.open_url(permalink.as_ref());
18742                })
18743                .ok();
18744            }
18745            Err(err) => {
18746                let message = format!("Failed to open permalink: {err}");
18747
18748                anyhow::Result::<()>::Err(err).log_err();
18749
18750                if let Some(workspace) = workspace {
18751                    workspace
18752                        .update(cx, |workspace, cx| {
18753                            struct OpenPermalinkToLine;
18754
18755                            workspace.show_toast(
18756                                Toast::new(
18757                                    NotificationId::unique::<OpenPermalinkToLine>(),
18758                                    message,
18759                                ),
18760                                cx,
18761                            )
18762                        })
18763                        .ok();
18764                }
18765            }
18766        })
18767        .detach();
18768    }
18769
18770    pub fn insert_uuid_v4(
18771        &mut self,
18772        _: &InsertUuidV4,
18773        window: &mut Window,
18774        cx: &mut Context<Self>,
18775    ) {
18776        self.insert_uuid(UuidVersion::V4, window, cx);
18777    }
18778
18779    pub fn insert_uuid_v7(
18780        &mut self,
18781        _: &InsertUuidV7,
18782        window: &mut Window,
18783        cx: &mut Context<Self>,
18784    ) {
18785        self.insert_uuid(UuidVersion::V7, window, cx);
18786    }
18787
18788    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18789        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18790        self.transact(window, cx, |this, window, cx| {
18791            let edits = this
18792                .selections
18793                .all::<Point>(cx)
18794                .into_iter()
18795                .map(|selection| {
18796                    let uuid = match version {
18797                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18798                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18799                    };
18800
18801                    (selection.range(), uuid.to_string())
18802                });
18803            this.edit(edits, cx);
18804            this.refresh_inline_completion(true, false, window, cx);
18805        });
18806    }
18807
18808    pub fn open_selections_in_multibuffer(
18809        &mut self,
18810        _: &OpenSelectionsInMultibuffer,
18811        window: &mut Window,
18812        cx: &mut Context<Self>,
18813    ) {
18814        let multibuffer = self.buffer.read(cx);
18815
18816        let Some(buffer) = multibuffer.as_singleton() else {
18817            return;
18818        };
18819
18820        let Some(workspace) = self.workspace() else {
18821            return;
18822        };
18823
18824        let title = multibuffer.title(cx).to_string();
18825
18826        let locations = self
18827            .selections
18828            .all_anchors(cx)
18829            .into_iter()
18830            .map(|selection| Location {
18831                buffer: buffer.clone(),
18832                range: selection.start.text_anchor..selection.end.text_anchor,
18833            })
18834            .collect::<Vec<_>>();
18835
18836        cx.spawn_in(window, async move |_, cx| {
18837            workspace.update_in(cx, |workspace, window, cx| {
18838                Self::open_locations_in_multibuffer(
18839                    workspace,
18840                    locations,
18841                    format!("Selections for '{title}'"),
18842                    false,
18843                    MultibufferSelectionMode::All,
18844                    window,
18845                    cx,
18846                );
18847            })
18848        })
18849        .detach();
18850    }
18851
18852    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18853    /// last highlight added will be used.
18854    ///
18855    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18856    pub fn highlight_rows<T: 'static>(
18857        &mut self,
18858        range: Range<Anchor>,
18859        color: Hsla,
18860        options: RowHighlightOptions,
18861        cx: &mut Context<Self>,
18862    ) {
18863        let snapshot = self.buffer().read(cx).snapshot(cx);
18864        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18865        let ix = row_highlights.binary_search_by(|highlight| {
18866            Ordering::Equal
18867                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18868                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18869        });
18870
18871        if let Err(mut ix) = ix {
18872            let index = post_inc(&mut self.highlight_order);
18873
18874            // If this range intersects with the preceding highlight, then merge it with
18875            // the preceding highlight. Otherwise insert a new highlight.
18876            let mut merged = false;
18877            if ix > 0 {
18878                let prev_highlight = &mut row_highlights[ix - 1];
18879                if prev_highlight
18880                    .range
18881                    .end
18882                    .cmp(&range.start, &snapshot)
18883                    .is_ge()
18884                {
18885                    ix -= 1;
18886                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18887                        prev_highlight.range.end = range.end;
18888                    }
18889                    merged = true;
18890                    prev_highlight.index = index;
18891                    prev_highlight.color = color;
18892                    prev_highlight.options = options;
18893                }
18894            }
18895
18896            if !merged {
18897                row_highlights.insert(
18898                    ix,
18899                    RowHighlight {
18900                        range: range.clone(),
18901                        index,
18902                        color,
18903                        options,
18904                        type_id: TypeId::of::<T>(),
18905                    },
18906                );
18907            }
18908
18909            // If any of the following highlights intersect with this one, merge them.
18910            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18911                let highlight = &row_highlights[ix];
18912                if next_highlight
18913                    .range
18914                    .start
18915                    .cmp(&highlight.range.end, &snapshot)
18916                    .is_le()
18917                {
18918                    if next_highlight
18919                        .range
18920                        .end
18921                        .cmp(&highlight.range.end, &snapshot)
18922                        .is_gt()
18923                    {
18924                        row_highlights[ix].range.end = next_highlight.range.end;
18925                    }
18926                    row_highlights.remove(ix + 1);
18927                } else {
18928                    break;
18929                }
18930            }
18931        }
18932    }
18933
18934    /// Remove any highlighted row ranges of the given type that intersect the
18935    /// given ranges.
18936    pub fn remove_highlighted_rows<T: 'static>(
18937        &mut self,
18938        ranges_to_remove: Vec<Range<Anchor>>,
18939        cx: &mut Context<Self>,
18940    ) {
18941        let snapshot = self.buffer().read(cx).snapshot(cx);
18942        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18943        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18944        row_highlights.retain(|highlight| {
18945            while let Some(range_to_remove) = ranges_to_remove.peek() {
18946                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18947                    Ordering::Less | Ordering::Equal => {
18948                        ranges_to_remove.next();
18949                    }
18950                    Ordering::Greater => {
18951                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18952                            Ordering::Less | Ordering::Equal => {
18953                                return false;
18954                            }
18955                            Ordering::Greater => break,
18956                        }
18957                    }
18958                }
18959            }
18960
18961            true
18962        })
18963    }
18964
18965    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18966    pub fn clear_row_highlights<T: 'static>(&mut self) {
18967        self.highlighted_rows.remove(&TypeId::of::<T>());
18968    }
18969
18970    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18971    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18972        self.highlighted_rows
18973            .get(&TypeId::of::<T>())
18974            .map_or(&[] as &[_], |vec| vec.as_slice())
18975            .iter()
18976            .map(|highlight| (highlight.range.clone(), highlight.color))
18977    }
18978
18979    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18980    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18981    /// Allows to ignore certain kinds of highlights.
18982    pub fn highlighted_display_rows(
18983        &self,
18984        window: &mut Window,
18985        cx: &mut App,
18986    ) -> BTreeMap<DisplayRow, LineHighlight> {
18987        let snapshot = self.snapshot(window, cx);
18988        let mut used_highlight_orders = HashMap::default();
18989        self.highlighted_rows
18990            .iter()
18991            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18992            .fold(
18993                BTreeMap::<DisplayRow, LineHighlight>::new(),
18994                |mut unique_rows, highlight| {
18995                    let start = highlight.range.start.to_display_point(&snapshot);
18996                    let end = highlight.range.end.to_display_point(&snapshot);
18997                    let start_row = start.row().0;
18998                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18999                        && end.column() == 0
19000                    {
19001                        end.row().0.saturating_sub(1)
19002                    } else {
19003                        end.row().0
19004                    };
19005                    for row in start_row..=end_row {
19006                        let used_index =
19007                            used_highlight_orders.entry(row).or_insert(highlight.index);
19008                        if highlight.index >= *used_index {
19009                            *used_index = highlight.index;
19010                            unique_rows.insert(
19011                                DisplayRow(row),
19012                                LineHighlight {
19013                                    include_gutter: highlight.options.include_gutter,
19014                                    border: None,
19015                                    background: highlight.color.into(),
19016                                    type_id: Some(highlight.type_id),
19017                                },
19018                            );
19019                        }
19020                    }
19021                    unique_rows
19022                },
19023            )
19024    }
19025
19026    pub fn highlighted_display_row_for_autoscroll(
19027        &self,
19028        snapshot: &DisplaySnapshot,
19029    ) -> Option<DisplayRow> {
19030        self.highlighted_rows
19031            .values()
19032            .flat_map(|highlighted_rows| highlighted_rows.iter())
19033            .filter_map(|highlight| {
19034                if highlight.options.autoscroll {
19035                    Some(highlight.range.start.to_display_point(snapshot).row())
19036                } else {
19037                    None
19038                }
19039            })
19040            .min()
19041    }
19042
19043    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19044        self.highlight_background::<SearchWithinRange>(
19045            ranges,
19046            |colors| colors.colors().editor_document_highlight_read_background,
19047            cx,
19048        )
19049    }
19050
19051    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19052        self.breadcrumb_header = Some(new_header);
19053    }
19054
19055    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19056        self.clear_background_highlights::<SearchWithinRange>(cx);
19057    }
19058
19059    pub fn highlight_background<T: 'static>(
19060        &mut self,
19061        ranges: &[Range<Anchor>],
19062        color_fetcher: fn(&Theme) -> Hsla,
19063        cx: &mut Context<Self>,
19064    ) {
19065        self.background_highlights.insert(
19066            HighlightKey::Type(TypeId::of::<T>()),
19067            (color_fetcher, Arc::from(ranges)),
19068        );
19069        self.scrollbar_marker_state.dirty = true;
19070        cx.notify();
19071    }
19072
19073    pub fn highlight_background_key<T: 'static>(
19074        &mut self,
19075        key: usize,
19076        ranges: &[Range<Anchor>],
19077        color_fetcher: fn(&Theme) -> Hsla,
19078        cx: &mut Context<Self>,
19079    ) {
19080        self.background_highlights.insert(
19081            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19082            (color_fetcher, Arc::from(ranges)),
19083        );
19084        self.scrollbar_marker_state.dirty = true;
19085        cx.notify();
19086    }
19087
19088    pub fn clear_background_highlights<T: 'static>(
19089        &mut self,
19090        cx: &mut Context<Self>,
19091    ) -> Option<BackgroundHighlight> {
19092        let text_highlights = self
19093            .background_highlights
19094            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19095        if !text_highlights.1.is_empty() {
19096            self.scrollbar_marker_state.dirty = true;
19097            cx.notify();
19098        }
19099        Some(text_highlights)
19100    }
19101
19102    pub fn highlight_gutter<T: 'static>(
19103        &mut self,
19104        ranges: impl Into<Vec<Range<Anchor>>>,
19105        color_fetcher: fn(&App) -> Hsla,
19106        cx: &mut Context<Self>,
19107    ) {
19108        self.gutter_highlights
19109            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19110        cx.notify();
19111    }
19112
19113    pub fn clear_gutter_highlights<T: 'static>(
19114        &mut self,
19115        cx: &mut Context<Self>,
19116    ) -> Option<GutterHighlight> {
19117        cx.notify();
19118        self.gutter_highlights.remove(&TypeId::of::<T>())
19119    }
19120
19121    pub fn insert_gutter_highlight<T: 'static>(
19122        &mut self,
19123        range: Range<Anchor>,
19124        color_fetcher: fn(&App) -> Hsla,
19125        cx: &mut Context<Self>,
19126    ) {
19127        let snapshot = self.buffer().read(cx).snapshot(cx);
19128        let mut highlights = self
19129            .gutter_highlights
19130            .remove(&TypeId::of::<T>())
19131            .map(|(_, highlights)| highlights)
19132            .unwrap_or_default();
19133        let ix = highlights.binary_search_by(|highlight| {
19134            Ordering::Equal
19135                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19136                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19137        });
19138        if let Err(ix) = ix {
19139            highlights.insert(ix, range);
19140        }
19141        self.gutter_highlights
19142            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19143    }
19144
19145    pub fn remove_gutter_highlights<T: 'static>(
19146        &mut self,
19147        ranges_to_remove: Vec<Range<Anchor>>,
19148        cx: &mut Context<Self>,
19149    ) {
19150        let snapshot = self.buffer().read(cx).snapshot(cx);
19151        let Some((color_fetcher, mut gutter_highlights)) =
19152            self.gutter_highlights.remove(&TypeId::of::<T>())
19153        else {
19154            return;
19155        };
19156        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19157        gutter_highlights.retain(|highlight| {
19158            while let Some(range_to_remove) = ranges_to_remove.peek() {
19159                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19160                    Ordering::Less | Ordering::Equal => {
19161                        ranges_to_remove.next();
19162                    }
19163                    Ordering::Greater => {
19164                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19165                            Ordering::Less | Ordering::Equal => {
19166                                return false;
19167                            }
19168                            Ordering::Greater => break,
19169                        }
19170                    }
19171                }
19172            }
19173
19174            true
19175        });
19176        self.gutter_highlights
19177            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19178    }
19179
19180    #[cfg(feature = "test-support")]
19181    pub fn all_text_highlights(
19182        &self,
19183        window: &mut Window,
19184        cx: &mut Context<Self>,
19185    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19186        let snapshot = self.snapshot(window, cx);
19187        self.display_map.update(cx, |display_map, _| {
19188            display_map
19189                .all_text_highlights()
19190                .map(|highlight| {
19191                    let (style, ranges) = highlight.as_ref();
19192                    (
19193                        *style,
19194                        ranges
19195                            .iter()
19196                            .map(|range| range.clone().to_display_points(&snapshot))
19197                            .collect(),
19198                    )
19199                })
19200                .collect()
19201        })
19202    }
19203
19204    #[cfg(feature = "test-support")]
19205    pub fn all_text_background_highlights(
19206        &self,
19207        window: &mut Window,
19208        cx: &mut Context<Self>,
19209    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19210        let snapshot = self.snapshot(window, cx);
19211        let buffer = &snapshot.buffer_snapshot;
19212        let start = buffer.anchor_before(0);
19213        let end = buffer.anchor_after(buffer.len());
19214        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19215    }
19216
19217    #[cfg(feature = "test-support")]
19218    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19219        let snapshot = self.buffer().read(cx).snapshot(cx);
19220
19221        let highlights = self
19222            .background_highlights
19223            .get(&HighlightKey::Type(TypeId::of::<
19224                items::BufferSearchHighlights,
19225            >()));
19226
19227        if let Some((_color, ranges)) = highlights {
19228            ranges
19229                .iter()
19230                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19231                .collect_vec()
19232        } else {
19233            vec![]
19234        }
19235    }
19236
19237    fn document_highlights_for_position<'a>(
19238        &'a self,
19239        position: Anchor,
19240        buffer: &'a MultiBufferSnapshot,
19241    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19242        let read_highlights = self
19243            .background_highlights
19244            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19245            .map(|h| &h.1);
19246        let write_highlights = self
19247            .background_highlights
19248            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19249            .map(|h| &h.1);
19250        let left_position = position.bias_left(buffer);
19251        let right_position = position.bias_right(buffer);
19252        read_highlights
19253            .into_iter()
19254            .chain(write_highlights)
19255            .flat_map(move |ranges| {
19256                let start_ix = match ranges.binary_search_by(|probe| {
19257                    let cmp = probe.end.cmp(&left_position, buffer);
19258                    if cmp.is_ge() {
19259                        Ordering::Greater
19260                    } else {
19261                        Ordering::Less
19262                    }
19263                }) {
19264                    Ok(i) | Err(i) => i,
19265                };
19266
19267                ranges[start_ix..]
19268                    .iter()
19269                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19270            })
19271    }
19272
19273    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19274        self.background_highlights
19275            .get(&HighlightKey::Type(TypeId::of::<T>()))
19276            .map_or(false, |(_, highlights)| !highlights.is_empty())
19277    }
19278
19279    pub fn background_highlights_in_range(
19280        &self,
19281        search_range: Range<Anchor>,
19282        display_snapshot: &DisplaySnapshot,
19283        theme: &Theme,
19284    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19285        let mut results = Vec::new();
19286        for (color_fetcher, ranges) in self.background_highlights.values() {
19287            let color = color_fetcher(theme);
19288            let start_ix = match ranges.binary_search_by(|probe| {
19289                let cmp = probe
19290                    .end
19291                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19292                if cmp.is_gt() {
19293                    Ordering::Greater
19294                } else {
19295                    Ordering::Less
19296                }
19297            }) {
19298                Ok(i) | Err(i) => i,
19299            };
19300            for range in &ranges[start_ix..] {
19301                if range
19302                    .start
19303                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19304                    .is_ge()
19305                {
19306                    break;
19307                }
19308
19309                let start = range.start.to_display_point(display_snapshot);
19310                let end = range.end.to_display_point(display_snapshot);
19311                results.push((start..end, color))
19312            }
19313        }
19314        results
19315    }
19316
19317    pub fn background_highlight_row_ranges<T: 'static>(
19318        &self,
19319        search_range: Range<Anchor>,
19320        display_snapshot: &DisplaySnapshot,
19321        count: usize,
19322    ) -> Vec<RangeInclusive<DisplayPoint>> {
19323        let mut results = Vec::new();
19324        let Some((_, ranges)) = self
19325            .background_highlights
19326            .get(&HighlightKey::Type(TypeId::of::<T>()))
19327        else {
19328            return vec![];
19329        };
19330
19331        let start_ix = match ranges.binary_search_by(|probe| {
19332            let cmp = probe
19333                .end
19334                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19335            if cmp.is_gt() {
19336                Ordering::Greater
19337            } else {
19338                Ordering::Less
19339            }
19340        }) {
19341            Ok(i) | Err(i) => i,
19342        };
19343        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19344            if let (Some(start_display), Some(end_display)) = (start, end) {
19345                results.push(
19346                    start_display.to_display_point(display_snapshot)
19347                        ..=end_display.to_display_point(display_snapshot),
19348                );
19349            }
19350        };
19351        let mut start_row: Option<Point> = None;
19352        let mut end_row: Option<Point> = None;
19353        if ranges.len() > count {
19354            return Vec::new();
19355        }
19356        for range in &ranges[start_ix..] {
19357            if range
19358                .start
19359                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19360                .is_ge()
19361            {
19362                break;
19363            }
19364            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19365            if let Some(current_row) = &end_row {
19366                if end.row == current_row.row {
19367                    continue;
19368                }
19369            }
19370            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19371            if start_row.is_none() {
19372                assert_eq!(end_row, None);
19373                start_row = Some(start);
19374                end_row = Some(end);
19375                continue;
19376            }
19377            if let Some(current_end) = end_row.as_mut() {
19378                if start.row > current_end.row + 1 {
19379                    push_region(start_row, end_row);
19380                    start_row = Some(start);
19381                    end_row = Some(end);
19382                } else {
19383                    // Merge two hunks.
19384                    *current_end = end;
19385                }
19386            } else {
19387                unreachable!();
19388            }
19389        }
19390        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19391        push_region(start_row, end_row);
19392        results
19393    }
19394
19395    pub fn gutter_highlights_in_range(
19396        &self,
19397        search_range: Range<Anchor>,
19398        display_snapshot: &DisplaySnapshot,
19399        cx: &App,
19400    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19401        let mut results = Vec::new();
19402        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19403            let color = color_fetcher(cx);
19404            let start_ix = match ranges.binary_search_by(|probe| {
19405                let cmp = probe
19406                    .end
19407                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19408                if cmp.is_gt() {
19409                    Ordering::Greater
19410                } else {
19411                    Ordering::Less
19412                }
19413            }) {
19414                Ok(i) | Err(i) => i,
19415            };
19416            for range in &ranges[start_ix..] {
19417                if range
19418                    .start
19419                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19420                    .is_ge()
19421                {
19422                    break;
19423                }
19424
19425                let start = range.start.to_display_point(display_snapshot);
19426                let end = range.end.to_display_point(display_snapshot);
19427                results.push((start..end, color))
19428            }
19429        }
19430        results
19431    }
19432
19433    /// Get the text ranges corresponding to the redaction query
19434    pub fn redacted_ranges(
19435        &self,
19436        search_range: Range<Anchor>,
19437        display_snapshot: &DisplaySnapshot,
19438        cx: &App,
19439    ) -> Vec<Range<DisplayPoint>> {
19440        display_snapshot
19441            .buffer_snapshot
19442            .redacted_ranges(search_range, |file| {
19443                if let Some(file) = file {
19444                    file.is_private()
19445                        && EditorSettings::get(
19446                            Some(SettingsLocation {
19447                                worktree_id: file.worktree_id(cx),
19448                                path: file.path().as_ref(),
19449                            }),
19450                            cx,
19451                        )
19452                        .redact_private_values
19453                } else {
19454                    false
19455                }
19456            })
19457            .map(|range| {
19458                range.start.to_display_point(display_snapshot)
19459                    ..range.end.to_display_point(display_snapshot)
19460            })
19461            .collect()
19462    }
19463
19464    pub fn highlight_text_key<T: 'static>(
19465        &mut self,
19466        key: usize,
19467        ranges: Vec<Range<Anchor>>,
19468        style: HighlightStyle,
19469        cx: &mut Context<Self>,
19470    ) {
19471        self.display_map.update(cx, |map, _| {
19472            map.highlight_text(
19473                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19474                ranges,
19475                style,
19476            );
19477        });
19478        cx.notify();
19479    }
19480
19481    pub fn highlight_text<T: 'static>(
19482        &mut self,
19483        ranges: Vec<Range<Anchor>>,
19484        style: HighlightStyle,
19485        cx: &mut Context<Self>,
19486    ) {
19487        self.display_map.update(cx, |map, _| {
19488            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19489        });
19490        cx.notify();
19491    }
19492
19493    pub(crate) fn highlight_inlays<T: 'static>(
19494        &mut self,
19495        highlights: Vec<InlayHighlight>,
19496        style: HighlightStyle,
19497        cx: &mut Context<Self>,
19498    ) {
19499        self.display_map.update(cx, |map, _| {
19500            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19501        });
19502        cx.notify();
19503    }
19504
19505    pub fn text_highlights<'a, T: 'static>(
19506        &'a self,
19507        cx: &'a App,
19508    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19509        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19510    }
19511
19512    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19513        let cleared = self
19514            .display_map
19515            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19516        if cleared {
19517            cx.notify();
19518        }
19519    }
19520
19521    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19522        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19523            && self.focus_handle.is_focused(window)
19524    }
19525
19526    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19527        self.show_cursor_when_unfocused = is_enabled;
19528        cx.notify();
19529    }
19530
19531    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19532        cx.notify();
19533    }
19534
19535    fn on_debug_session_event(
19536        &mut self,
19537        _session: Entity<Session>,
19538        event: &SessionEvent,
19539        cx: &mut Context<Self>,
19540    ) {
19541        match event {
19542            SessionEvent::InvalidateInlineValue => {
19543                self.refresh_inline_values(cx);
19544            }
19545            _ => {}
19546        }
19547    }
19548
19549    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19550        let Some(project) = self.project.clone() else {
19551            return;
19552        };
19553
19554        if !self.inline_value_cache.enabled {
19555            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19556            self.splice_inlays(&inlays, Vec::new(), cx);
19557            return;
19558        }
19559
19560        let current_execution_position = self
19561            .highlighted_rows
19562            .get(&TypeId::of::<ActiveDebugLine>())
19563            .and_then(|lines| lines.last().map(|line| line.range.end));
19564
19565        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19566            let inline_values = editor
19567                .update(cx, |editor, cx| {
19568                    let Some(current_execution_position) = current_execution_position else {
19569                        return Some(Task::ready(Ok(Vec::new())));
19570                    };
19571
19572                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19573                        let snapshot = buffer.snapshot(cx);
19574
19575                        let excerpt = snapshot.excerpt_containing(
19576                            current_execution_position..current_execution_position,
19577                        )?;
19578
19579                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19580                    })?;
19581
19582                    let range =
19583                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19584
19585                    project.inline_values(buffer, range, cx)
19586                })
19587                .ok()
19588                .flatten()?
19589                .await
19590                .context("refreshing debugger inlays")
19591                .log_err()?;
19592
19593            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19594
19595            for (buffer_id, inline_value) in inline_values
19596                .into_iter()
19597                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19598            {
19599                buffer_inline_values
19600                    .entry(buffer_id)
19601                    .or_default()
19602                    .push(inline_value);
19603            }
19604
19605            editor
19606                .update(cx, |editor, cx| {
19607                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19608                    let mut new_inlays = Vec::default();
19609
19610                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19611                        let buffer_id = buffer_snapshot.remote_id();
19612                        buffer_inline_values
19613                            .get(&buffer_id)
19614                            .into_iter()
19615                            .flatten()
19616                            .for_each(|hint| {
19617                                let inlay = Inlay::debugger(
19618                                    post_inc(&mut editor.next_inlay_id),
19619                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19620                                    hint.text(),
19621                                );
19622
19623                                new_inlays.push(inlay);
19624                            });
19625                    }
19626
19627                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19628                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19629
19630                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19631                })
19632                .ok()?;
19633            Some(())
19634        });
19635    }
19636
19637    fn on_buffer_event(
19638        &mut self,
19639        multibuffer: &Entity<MultiBuffer>,
19640        event: &multi_buffer::Event,
19641        window: &mut Window,
19642        cx: &mut Context<Self>,
19643    ) {
19644        match event {
19645            multi_buffer::Event::Edited {
19646                singleton_buffer_edited,
19647                edited_buffer,
19648            } => {
19649                self.scrollbar_marker_state.dirty = true;
19650                self.active_indent_guides_state.dirty = true;
19651                self.refresh_active_diagnostics(cx);
19652                self.refresh_code_actions(window, cx);
19653                self.refresh_selected_text_highlights(true, window, cx);
19654                self.refresh_single_line_folds(window, cx);
19655                refresh_matching_bracket_highlights(self, window, cx);
19656                if self.has_active_inline_completion() {
19657                    self.update_visible_inline_completion(window, cx);
19658                }
19659                if let Some(project) = self.project.as_ref() {
19660                    if let Some(edited_buffer) = edited_buffer {
19661                        project.update(cx, |project, cx| {
19662                            self.registered_buffers
19663                                .entry(edited_buffer.read(cx).remote_id())
19664                                .or_insert_with(|| {
19665                                    project
19666                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19667                                });
19668                        });
19669                    }
19670                }
19671                cx.emit(EditorEvent::BufferEdited);
19672                cx.emit(SearchEvent::MatchesInvalidated);
19673
19674                if let Some(buffer) = edited_buffer {
19675                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19676                }
19677
19678                if *singleton_buffer_edited {
19679                    if let Some(buffer) = edited_buffer {
19680                        if buffer.read(cx).file().is_none() {
19681                            cx.emit(EditorEvent::TitleChanged);
19682                        }
19683                    }
19684                    if let Some(project) = &self.project {
19685                        #[allow(clippy::mutable_key_type)]
19686                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19687                            multibuffer
19688                                .all_buffers()
19689                                .into_iter()
19690                                .filter_map(|buffer| {
19691                                    buffer.update(cx, |buffer, cx| {
19692                                        let language = buffer.language()?;
19693                                        let should_discard = project.update(cx, |project, cx| {
19694                                            project.is_local()
19695                                                && !project.has_language_servers_for(buffer, cx)
19696                                        });
19697                                        should_discard.not().then_some(language.clone())
19698                                    })
19699                                })
19700                                .collect::<HashSet<_>>()
19701                        });
19702                        if !languages_affected.is_empty() {
19703                            self.refresh_inlay_hints(
19704                                InlayHintRefreshReason::BufferEdited(languages_affected),
19705                                cx,
19706                            );
19707                        }
19708                    }
19709                }
19710
19711                let Some(project) = &self.project else { return };
19712                let (telemetry, is_via_ssh) = {
19713                    let project = project.read(cx);
19714                    let telemetry = project.client().telemetry().clone();
19715                    let is_via_ssh = project.is_via_ssh();
19716                    (telemetry, is_via_ssh)
19717                };
19718                refresh_linked_ranges(self, window, cx);
19719                telemetry.log_edit_event("editor", is_via_ssh);
19720            }
19721            multi_buffer::Event::ExcerptsAdded {
19722                buffer,
19723                predecessor,
19724                excerpts,
19725            } => {
19726                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19727                let buffer_id = buffer.read(cx).remote_id();
19728                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19729                    if let Some(project) = &self.project {
19730                        update_uncommitted_diff_for_buffer(
19731                            cx.entity(),
19732                            project,
19733                            [buffer.clone()],
19734                            self.buffer.clone(),
19735                            cx,
19736                        )
19737                        .detach();
19738                    }
19739                }
19740                self.update_lsp_data(false, Some(buffer_id), window, cx);
19741                cx.emit(EditorEvent::ExcerptsAdded {
19742                    buffer: buffer.clone(),
19743                    predecessor: *predecessor,
19744                    excerpts: excerpts.clone(),
19745                });
19746                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19747            }
19748            multi_buffer::Event::ExcerptsRemoved {
19749                ids,
19750                removed_buffer_ids,
19751            } => {
19752                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19753                let buffer = self.buffer.read(cx);
19754                self.registered_buffers
19755                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19756                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19757                cx.emit(EditorEvent::ExcerptsRemoved {
19758                    ids: ids.clone(),
19759                    removed_buffer_ids: removed_buffer_ids.clone(),
19760                });
19761            }
19762            multi_buffer::Event::ExcerptsEdited {
19763                excerpt_ids,
19764                buffer_ids,
19765            } => {
19766                self.display_map.update(cx, |map, cx| {
19767                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19768                });
19769                cx.emit(EditorEvent::ExcerptsEdited {
19770                    ids: excerpt_ids.clone(),
19771                });
19772            }
19773            multi_buffer::Event::ExcerptsExpanded { ids } => {
19774                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19775                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19776            }
19777            multi_buffer::Event::Reparsed(buffer_id) => {
19778                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19779                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19780
19781                cx.emit(EditorEvent::Reparsed(*buffer_id));
19782            }
19783            multi_buffer::Event::DiffHunksToggled => {
19784                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19785            }
19786            multi_buffer::Event::LanguageChanged(buffer_id) => {
19787                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19788                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19789                cx.emit(EditorEvent::Reparsed(*buffer_id));
19790                cx.notify();
19791            }
19792            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19793            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19794            multi_buffer::Event::FileHandleChanged
19795            | multi_buffer::Event::Reloaded
19796            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19797            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19798            multi_buffer::Event::DiagnosticsUpdated => {
19799                self.update_diagnostics_state(window, cx);
19800            }
19801            _ => {}
19802        };
19803    }
19804
19805    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19806        if !self.diagnostics_enabled() {
19807            return;
19808        }
19809        self.refresh_active_diagnostics(cx);
19810        self.refresh_inline_diagnostics(true, window, cx);
19811        self.scrollbar_marker_state.dirty = true;
19812        cx.notify();
19813    }
19814
19815    pub fn start_temporary_diff_override(&mut self) {
19816        self.load_diff_task.take();
19817        self.temporary_diff_override = true;
19818    }
19819
19820    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19821        self.temporary_diff_override = false;
19822        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19823        self.buffer.update(cx, |buffer, cx| {
19824            buffer.set_all_diff_hunks_collapsed(cx);
19825        });
19826
19827        if let Some(project) = self.project.clone() {
19828            self.load_diff_task = Some(
19829                update_uncommitted_diff_for_buffer(
19830                    cx.entity(),
19831                    &project,
19832                    self.buffer.read(cx).all_buffers(),
19833                    self.buffer.clone(),
19834                    cx,
19835                )
19836                .shared(),
19837            );
19838        }
19839    }
19840
19841    fn on_display_map_changed(
19842        &mut self,
19843        _: Entity<DisplayMap>,
19844        _: &mut Window,
19845        cx: &mut Context<Self>,
19846    ) {
19847        cx.notify();
19848    }
19849
19850    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19851        let new_severity = if self.diagnostics_enabled() {
19852            EditorSettings::get_global(cx)
19853                .diagnostics_max_severity
19854                .unwrap_or(DiagnosticSeverity::Hint)
19855        } else {
19856            DiagnosticSeverity::Off
19857        };
19858        self.set_max_diagnostics_severity(new_severity, cx);
19859        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19860        self.update_edit_prediction_settings(cx);
19861        self.refresh_inline_completion(true, false, window, cx);
19862        self.refresh_inline_values(cx);
19863        self.refresh_inlay_hints(
19864            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19865                self.selections.newest_anchor().head(),
19866                &self.buffer.read(cx).snapshot(cx),
19867                cx,
19868            )),
19869            cx,
19870        );
19871
19872        let old_cursor_shape = self.cursor_shape;
19873
19874        {
19875            let editor_settings = EditorSettings::get_global(cx);
19876            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19877            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19878            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19879            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19880        }
19881
19882        if old_cursor_shape != self.cursor_shape {
19883            cx.emit(EditorEvent::CursorShapeChanged);
19884        }
19885
19886        let project_settings = ProjectSettings::get_global(cx);
19887        self.serialize_dirty_buffers =
19888            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19889
19890        if self.mode.is_full() {
19891            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19892            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19893            if self.show_inline_diagnostics != show_inline_diagnostics {
19894                self.show_inline_diagnostics = show_inline_diagnostics;
19895                self.refresh_inline_diagnostics(false, window, cx);
19896            }
19897
19898            if self.git_blame_inline_enabled != inline_blame_enabled {
19899                self.toggle_git_blame_inline_internal(false, window, cx);
19900            }
19901
19902            let minimap_settings = EditorSettings::get_global(cx).minimap;
19903            if self.minimap_visibility != MinimapVisibility::Disabled {
19904                if self.minimap_visibility.settings_visibility()
19905                    != minimap_settings.minimap_enabled()
19906                {
19907                    self.set_minimap_visibility(
19908                        MinimapVisibility::for_mode(self.mode(), cx),
19909                        window,
19910                        cx,
19911                    );
19912                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19913                    minimap_entity.update(cx, |minimap_editor, cx| {
19914                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19915                    })
19916                }
19917            }
19918        }
19919
19920        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19921            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19922        }) {
19923            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19924                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19925            }
19926            self.refresh_colors(false, None, window, cx);
19927        }
19928
19929        cx.notify();
19930    }
19931
19932    pub fn set_searchable(&mut self, searchable: bool) {
19933        self.searchable = searchable;
19934    }
19935
19936    pub fn searchable(&self) -> bool {
19937        self.searchable
19938    }
19939
19940    fn open_proposed_changes_editor(
19941        &mut self,
19942        _: &OpenProposedChangesEditor,
19943        window: &mut Window,
19944        cx: &mut Context<Self>,
19945    ) {
19946        let Some(workspace) = self.workspace() else {
19947            cx.propagate();
19948            return;
19949        };
19950
19951        let selections = self.selections.all::<usize>(cx);
19952        let multi_buffer = self.buffer.read(cx);
19953        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19954        let mut new_selections_by_buffer = HashMap::default();
19955        for selection in selections {
19956            for (buffer, range, _) in
19957                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19958            {
19959                let mut range = range.to_point(buffer);
19960                range.start.column = 0;
19961                range.end.column = buffer.line_len(range.end.row);
19962                new_selections_by_buffer
19963                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19964                    .or_insert(Vec::new())
19965                    .push(range)
19966            }
19967        }
19968
19969        let proposed_changes_buffers = new_selections_by_buffer
19970            .into_iter()
19971            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19972            .collect::<Vec<_>>();
19973        let proposed_changes_editor = cx.new(|cx| {
19974            ProposedChangesEditor::new(
19975                "Proposed changes",
19976                proposed_changes_buffers,
19977                self.project.clone(),
19978                window,
19979                cx,
19980            )
19981        });
19982
19983        window.defer(cx, move |window, cx| {
19984            workspace.update(cx, |workspace, cx| {
19985                workspace.active_pane().update(cx, |pane, cx| {
19986                    pane.add_item(
19987                        Box::new(proposed_changes_editor),
19988                        true,
19989                        true,
19990                        None,
19991                        window,
19992                        cx,
19993                    );
19994                });
19995            });
19996        });
19997    }
19998
19999    pub fn open_excerpts_in_split(
20000        &mut self,
20001        _: &OpenExcerptsSplit,
20002        window: &mut Window,
20003        cx: &mut Context<Self>,
20004    ) {
20005        self.open_excerpts_common(None, true, window, cx)
20006    }
20007
20008    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20009        self.open_excerpts_common(None, false, window, cx)
20010    }
20011
20012    fn open_excerpts_common(
20013        &mut self,
20014        jump_data: Option<JumpData>,
20015        split: bool,
20016        window: &mut Window,
20017        cx: &mut Context<Self>,
20018    ) {
20019        let Some(workspace) = self.workspace() else {
20020            cx.propagate();
20021            return;
20022        };
20023
20024        if self.buffer.read(cx).is_singleton() {
20025            cx.propagate();
20026            return;
20027        }
20028
20029        let mut new_selections_by_buffer = HashMap::default();
20030        match &jump_data {
20031            Some(JumpData::MultiBufferPoint {
20032                excerpt_id,
20033                position,
20034                anchor,
20035                line_offset_from_top,
20036            }) => {
20037                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20038                if let Some(buffer) = multi_buffer_snapshot
20039                    .buffer_id_for_excerpt(*excerpt_id)
20040                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20041                {
20042                    let buffer_snapshot = buffer.read(cx).snapshot();
20043                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20044                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20045                    } else {
20046                        buffer_snapshot.clip_point(*position, Bias::Left)
20047                    };
20048                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20049                    new_selections_by_buffer.insert(
20050                        buffer,
20051                        (
20052                            vec![jump_to_offset..jump_to_offset],
20053                            Some(*line_offset_from_top),
20054                        ),
20055                    );
20056                }
20057            }
20058            Some(JumpData::MultiBufferRow {
20059                row,
20060                line_offset_from_top,
20061            }) => {
20062                let point = MultiBufferPoint::new(row.0, 0);
20063                if let Some((buffer, buffer_point, _)) =
20064                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20065                {
20066                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20067                    new_selections_by_buffer
20068                        .entry(buffer)
20069                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20070                        .0
20071                        .push(buffer_offset..buffer_offset)
20072                }
20073            }
20074            None => {
20075                let selections = self.selections.all::<usize>(cx);
20076                let multi_buffer = self.buffer.read(cx);
20077                for selection in selections {
20078                    for (snapshot, range, _, anchor) in multi_buffer
20079                        .snapshot(cx)
20080                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20081                    {
20082                        if let Some(anchor) = anchor {
20083                            // selection is in a deleted hunk
20084                            let Some(buffer_id) = anchor.buffer_id else {
20085                                continue;
20086                            };
20087                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20088                                continue;
20089                            };
20090                            let offset = text::ToOffset::to_offset(
20091                                &anchor.text_anchor,
20092                                &buffer_handle.read(cx).snapshot(),
20093                            );
20094                            let range = offset..offset;
20095                            new_selections_by_buffer
20096                                .entry(buffer_handle)
20097                                .or_insert((Vec::new(), None))
20098                                .0
20099                                .push(range)
20100                        } else {
20101                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20102                            else {
20103                                continue;
20104                            };
20105                            new_selections_by_buffer
20106                                .entry(buffer_handle)
20107                                .or_insert((Vec::new(), None))
20108                                .0
20109                                .push(range)
20110                        }
20111                    }
20112                }
20113            }
20114        }
20115
20116        new_selections_by_buffer
20117            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20118
20119        if new_selections_by_buffer.is_empty() {
20120            return;
20121        }
20122
20123        // We defer the pane interaction because we ourselves are a workspace item
20124        // and activating a new item causes the pane to call a method on us reentrantly,
20125        // which panics if we're on the stack.
20126        window.defer(cx, move |window, cx| {
20127            workspace.update(cx, |workspace, cx| {
20128                let pane = if split {
20129                    workspace.adjacent_pane(window, cx)
20130                } else {
20131                    workspace.active_pane().clone()
20132                };
20133
20134                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20135                    let editor = buffer
20136                        .read(cx)
20137                        .file()
20138                        .is_none()
20139                        .then(|| {
20140                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20141                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20142                            // Instead, we try to activate the existing editor in the pane first.
20143                            let (editor, pane_item_index) =
20144                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20145                                    let editor = item.downcast::<Editor>()?;
20146                                    let singleton_buffer =
20147                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20148                                    if singleton_buffer == buffer {
20149                                        Some((editor, i))
20150                                    } else {
20151                                        None
20152                                    }
20153                                })?;
20154                            pane.update(cx, |pane, cx| {
20155                                pane.activate_item(pane_item_index, true, true, window, cx)
20156                            });
20157                            Some(editor)
20158                        })
20159                        .flatten()
20160                        .unwrap_or_else(|| {
20161                            workspace.open_project_item::<Self>(
20162                                pane.clone(),
20163                                buffer,
20164                                true,
20165                                true,
20166                                window,
20167                                cx,
20168                            )
20169                        });
20170
20171                    editor.update(cx, |editor, cx| {
20172                        let autoscroll = match scroll_offset {
20173                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20174                            None => Autoscroll::newest(),
20175                        };
20176                        let nav_history = editor.nav_history.take();
20177                        editor.change_selections(
20178                            SelectionEffects::scroll(autoscroll),
20179                            window,
20180                            cx,
20181                            |s| {
20182                                s.select_ranges(ranges);
20183                            },
20184                        );
20185                        editor.nav_history = nav_history;
20186                    });
20187                }
20188            })
20189        });
20190    }
20191
20192    // For now, don't allow opening excerpts in buffers that aren't backed by
20193    // regular project files.
20194    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20195        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20196    }
20197
20198    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20199        let snapshot = self.buffer.read(cx).read(cx);
20200        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20201        Some(
20202            ranges
20203                .iter()
20204                .map(move |range| {
20205                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20206                })
20207                .collect(),
20208        )
20209    }
20210
20211    fn selection_replacement_ranges(
20212        &self,
20213        range: Range<OffsetUtf16>,
20214        cx: &mut App,
20215    ) -> Vec<Range<OffsetUtf16>> {
20216        let selections = self.selections.all::<OffsetUtf16>(cx);
20217        let newest_selection = selections
20218            .iter()
20219            .max_by_key(|selection| selection.id)
20220            .unwrap();
20221        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20222        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20223        let snapshot = self.buffer.read(cx).read(cx);
20224        selections
20225            .into_iter()
20226            .map(|mut selection| {
20227                selection.start.0 =
20228                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20229                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20230                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20231                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20232            })
20233            .collect()
20234    }
20235
20236    fn report_editor_event(
20237        &self,
20238        event_type: &'static str,
20239        file_extension: Option<String>,
20240        cx: &App,
20241    ) {
20242        if cfg!(any(test, feature = "test-support")) {
20243            return;
20244        }
20245
20246        let Some(project) = &self.project else { return };
20247
20248        // If None, we are in a file without an extension
20249        let file = self
20250            .buffer
20251            .read(cx)
20252            .as_singleton()
20253            .and_then(|b| b.read(cx).file());
20254        let file_extension = file_extension.or(file
20255            .as_ref()
20256            .and_then(|file| Path::new(file.file_name(cx)).extension())
20257            .and_then(|e| e.to_str())
20258            .map(|a| a.to_string()));
20259
20260        let vim_mode = vim_enabled(cx);
20261
20262        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20263        let copilot_enabled = edit_predictions_provider
20264            == language::language_settings::EditPredictionProvider::Copilot;
20265        let copilot_enabled_for_language = self
20266            .buffer
20267            .read(cx)
20268            .language_settings(cx)
20269            .show_edit_predictions;
20270
20271        let project = project.read(cx);
20272        telemetry::event!(
20273            event_type,
20274            file_extension,
20275            vim_mode,
20276            copilot_enabled,
20277            copilot_enabled_for_language,
20278            edit_predictions_provider,
20279            is_via_ssh = project.is_via_ssh(),
20280        );
20281    }
20282
20283    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20284    /// with each line being an array of {text, highlight} objects.
20285    fn copy_highlight_json(
20286        &mut self,
20287        _: &CopyHighlightJson,
20288        window: &mut Window,
20289        cx: &mut Context<Self>,
20290    ) {
20291        #[derive(Serialize)]
20292        struct Chunk<'a> {
20293            text: String,
20294            highlight: Option<&'a str>,
20295        }
20296
20297        let snapshot = self.buffer.read(cx).snapshot(cx);
20298        let range = self
20299            .selected_text_range(false, window, cx)
20300            .and_then(|selection| {
20301                if selection.range.is_empty() {
20302                    None
20303                } else {
20304                    Some(selection.range)
20305                }
20306            })
20307            .unwrap_or_else(|| 0..snapshot.len());
20308
20309        let chunks = snapshot.chunks(range, true);
20310        let mut lines = Vec::new();
20311        let mut line: VecDeque<Chunk> = VecDeque::new();
20312
20313        let Some(style) = self.style.as_ref() else {
20314            return;
20315        };
20316
20317        for chunk in chunks {
20318            let highlight = chunk
20319                .syntax_highlight_id
20320                .and_then(|id| id.name(&style.syntax));
20321            let mut chunk_lines = chunk.text.split('\n').peekable();
20322            while let Some(text) = chunk_lines.next() {
20323                let mut merged_with_last_token = false;
20324                if let Some(last_token) = line.back_mut() {
20325                    if last_token.highlight == highlight {
20326                        last_token.text.push_str(text);
20327                        merged_with_last_token = true;
20328                    }
20329                }
20330
20331                if !merged_with_last_token {
20332                    line.push_back(Chunk {
20333                        text: text.into(),
20334                        highlight,
20335                    });
20336                }
20337
20338                if chunk_lines.peek().is_some() {
20339                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20340                        line.pop_front();
20341                    }
20342                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20343                        line.pop_back();
20344                    }
20345
20346                    lines.push(mem::take(&mut line));
20347                }
20348            }
20349        }
20350
20351        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20352            return;
20353        };
20354        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20355    }
20356
20357    pub fn open_context_menu(
20358        &mut self,
20359        _: &OpenContextMenu,
20360        window: &mut Window,
20361        cx: &mut Context<Self>,
20362    ) {
20363        self.request_autoscroll(Autoscroll::newest(), cx);
20364        let position = self.selections.newest_display(cx).start;
20365        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20366    }
20367
20368    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20369        &self.inlay_hint_cache
20370    }
20371
20372    pub fn replay_insert_event(
20373        &mut self,
20374        text: &str,
20375        relative_utf16_range: Option<Range<isize>>,
20376        window: &mut Window,
20377        cx: &mut Context<Self>,
20378    ) {
20379        if !self.input_enabled {
20380            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20381            return;
20382        }
20383        if let Some(relative_utf16_range) = relative_utf16_range {
20384            let selections = self.selections.all::<OffsetUtf16>(cx);
20385            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20386                let new_ranges = selections.into_iter().map(|range| {
20387                    let start = OffsetUtf16(
20388                        range
20389                            .head()
20390                            .0
20391                            .saturating_add_signed(relative_utf16_range.start),
20392                    );
20393                    let end = OffsetUtf16(
20394                        range
20395                            .head()
20396                            .0
20397                            .saturating_add_signed(relative_utf16_range.end),
20398                    );
20399                    start..end
20400                });
20401                s.select_ranges(new_ranges);
20402            });
20403        }
20404
20405        self.handle_input(text, window, cx);
20406    }
20407
20408    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20409        let Some(provider) = self.semantics_provider.as_ref() else {
20410            return false;
20411        };
20412
20413        let mut supports = false;
20414        self.buffer().update(cx, |this, cx| {
20415            this.for_each_buffer(|buffer| {
20416                supports |= provider.supports_inlay_hints(buffer, cx);
20417            });
20418        });
20419
20420        supports
20421    }
20422
20423    pub fn is_focused(&self, window: &Window) -> bool {
20424        self.focus_handle.is_focused(window)
20425    }
20426
20427    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20428        cx.emit(EditorEvent::Focused);
20429
20430        if let Some(descendant) = self
20431            .last_focused_descendant
20432            .take()
20433            .and_then(|descendant| descendant.upgrade())
20434        {
20435            window.focus(&descendant);
20436        } else {
20437            if let Some(blame) = self.blame.as_ref() {
20438                blame.update(cx, GitBlame::focus)
20439            }
20440
20441            self.blink_manager.update(cx, BlinkManager::enable);
20442            self.show_cursor_names(window, cx);
20443            self.buffer.update(cx, |buffer, cx| {
20444                buffer.finalize_last_transaction(cx);
20445                if self.leader_id.is_none() {
20446                    buffer.set_active_selections(
20447                        &self.selections.disjoint_anchors(),
20448                        self.selections.line_mode,
20449                        self.cursor_shape,
20450                        cx,
20451                    );
20452                }
20453            });
20454        }
20455    }
20456
20457    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20458        cx.emit(EditorEvent::FocusedIn)
20459    }
20460
20461    fn handle_focus_out(
20462        &mut self,
20463        event: FocusOutEvent,
20464        _window: &mut Window,
20465        cx: &mut Context<Self>,
20466    ) {
20467        if event.blurred != self.focus_handle {
20468            self.last_focused_descendant = Some(event.blurred);
20469        }
20470        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20471    }
20472
20473    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20474        self.blink_manager.update(cx, BlinkManager::disable);
20475        self.buffer
20476            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20477
20478        if let Some(blame) = self.blame.as_ref() {
20479            blame.update(cx, GitBlame::blur)
20480        }
20481        if !self.hover_state.focused(window, cx) {
20482            hide_hover(self, cx);
20483        }
20484        if !self
20485            .context_menu
20486            .borrow()
20487            .as_ref()
20488            .is_some_and(|context_menu| context_menu.focused(window, cx))
20489        {
20490            self.hide_context_menu(window, cx);
20491        }
20492        self.discard_inline_completion(false, cx);
20493        cx.emit(EditorEvent::Blurred);
20494        cx.notify();
20495    }
20496
20497    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20498        let mut pending: String = window
20499            .pending_input_keystrokes()
20500            .into_iter()
20501            .flatten()
20502            .filter_map(|keystroke| {
20503                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20504                    keystroke.key_char.clone()
20505                } else {
20506                    None
20507                }
20508            })
20509            .collect();
20510
20511        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20512            pending = "".to_string();
20513        }
20514
20515        let existing_pending = self
20516            .text_highlights::<PendingInput>(cx)
20517            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20518        if existing_pending.is_none() && pending.is_empty() {
20519            return;
20520        }
20521        let transaction =
20522            self.transact(window, cx, |this, window, cx| {
20523                let selections = this.selections.all::<usize>(cx);
20524                let edits = selections
20525                    .iter()
20526                    .map(|selection| (selection.end..selection.end, pending.clone()));
20527                this.edit(edits, cx);
20528                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20529                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20530                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20531                    }));
20532                });
20533                if let Some(existing_ranges) = existing_pending {
20534                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20535                    this.edit(edits, cx);
20536                }
20537            });
20538
20539        let snapshot = self.snapshot(window, cx);
20540        let ranges = self
20541            .selections
20542            .all::<usize>(cx)
20543            .into_iter()
20544            .map(|selection| {
20545                snapshot.buffer_snapshot.anchor_after(selection.end)
20546                    ..snapshot
20547                        .buffer_snapshot
20548                        .anchor_before(selection.end + pending.len())
20549            })
20550            .collect();
20551
20552        if pending.is_empty() {
20553            self.clear_highlights::<PendingInput>(cx);
20554        } else {
20555            self.highlight_text::<PendingInput>(
20556                ranges,
20557                HighlightStyle {
20558                    underline: Some(UnderlineStyle {
20559                        thickness: px(1.),
20560                        color: None,
20561                        wavy: false,
20562                    }),
20563                    ..Default::default()
20564                },
20565                cx,
20566            );
20567        }
20568
20569        self.ime_transaction = self.ime_transaction.or(transaction);
20570        if let Some(transaction) = self.ime_transaction {
20571            self.buffer.update(cx, |buffer, cx| {
20572                buffer.group_until_transaction(transaction, cx);
20573            });
20574        }
20575
20576        if self.text_highlights::<PendingInput>(cx).is_none() {
20577            self.ime_transaction.take();
20578        }
20579    }
20580
20581    pub fn register_action_renderer(
20582        &mut self,
20583        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20584    ) -> Subscription {
20585        let id = self.next_editor_action_id.post_inc();
20586        self.editor_actions
20587            .borrow_mut()
20588            .insert(id, Box::new(listener));
20589
20590        let editor_actions = self.editor_actions.clone();
20591        Subscription::new(move || {
20592            editor_actions.borrow_mut().remove(&id);
20593        })
20594    }
20595
20596    pub fn register_action<A: Action>(
20597        &mut self,
20598        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20599    ) -> Subscription {
20600        let id = self.next_editor_action_id.post_inc();
20601        let listener = Arc::new(listener);
20602        self.editor_actions.borrow_mut().insert(
20603            id,
20604            Box::new(move |_, window, _| {
20605                let listener = listener.clone();
20606                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20607                    let action = action.downcast_ref().unwrap();
20608                    if phase == DispatchPhase::Bubble {
20609                        listener(action, window, cx)
20610                    }
20611                })
20612            }),
20613        );
20614
20615        let editor_actions = self.editor_actions.clone();
20616        Subscription::new(move || {
20617            editor_actions.borrow_mut().remove(&id);
20618        })
20619    }
20620
20621    pub fn file_header_size(&self) -> u32 {
20622        FILE_HEADER_HEIGHT
20623    }
20624
20625    pub fn restore(
20626        &mut self,
20627        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20628        window: &mut Window,
20629        cx: &mut Context<Self>,
20630    ) {
20631        let workspace = self.workspace();
20632        let project = self.project.as_ref();
20633        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20634            let mut tasks = Vec::new();
20635            for (buffer_id, changes) in revert_changes {
20636                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20637                    buffer.update(cx, |buffer, cx| {
20638                        buffer.edit(
20639                            changes
20640                                .into_iter()
20641                                .map(|(range, text)| (range, text.to_string())),
20642                            None,
20643                            cx,
20644                        );
20645                    });
20646
20647                    if let Some(project) =
20648                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20649                    {
20650                        project.update(cx, |project, cx| {
20651                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20652                        })
20653                    }
20654                }
20655            }
20656            tasks
20657        });
20658        cx.spawn_in(window, async move |_, cx| {
20659            for (buffer, task) in save_tasks {
20660                let result = task.await;
20661                if result.is_err() {
20662                    let Some(path) = buffer
20663                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20664                        .ok()
20665                    else {
20666                        continue;
20667                    };
20668                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20669                        let Some(task) = cx
20670                            .update_window_entity(&workspace, |workspace, window, cx| {
20671                                workspace
20672                                    .open_path_preview(path, None, false, false, false, window, cx)
20673                            })
20674                            .ok()
20675                        else {
20676                            continue;
20677                        };
20678                        task.await.log_err();
20679                    }
20680                }
20681            }
20682        })
20683        .detach();
20684        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20685            selections.refresh()
20686        });
20687    }
20688
20689    pub fn to_pixel_point(
20690        &self,
20691        source: multi_buffer::Anchor,
20692        editor_snapshot: &EditorSnapshot,
20693        window: &mut Window,
20694    ) -> Option<gpui::Point<Pixels>> {
20695        let source_point = source.to_display_point(editor_snapshot);
20696        self.display_to_pixel_point(source_point, editor_snapshot, window)
20697    }
20698
20699    pub fn display_to_pixel_point(
20700        &self,
20701        source: DisplayPoint,
20702        editor_snapshot: &EditorSnapshot,
20703        window: &mut Window,
20704    ) -> Option<gpui::Point<Pixels>> {
20705        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20706        let text_layout_details = self.text_layout_details(window);
20707        let scroll_top = text_layout_details
20708            .scroll_anchor
20709            .scroll_position(editor_snapshot)
20710            .y;
20711
20712        if source.row().as_f32() < scroll_top.floor() {
20713            return None;
20714        }
20715        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20716        let source_y = line_height * (source.row().as_f32() - scroll_top);
20717        Some(gpui::Point::new(source_x, source_y))
20718    }
20719
20720    pub fn has_visible_completions_menu(&self) -> bool {
20721        !self.edit_prediction_preview_is_active()
20722            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20723                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20724            })
20725    }
20726
20727    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20728        if self.mode.is_minimap() {
20729            return;
20730        }
20731        self.addons
20732            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20733    }
20734
20735    pub fn unregister_addon<T: Addon>(&mut self) {
20736        self.addons.remove(&std::any::TypeId::of::<T>());
20737    }
20738
20739    pub fn addon<T: Addon>(&self) -> Option<&T> {
20740        let type_id = std::any::TypeId::of::<T>();
20741        self.addons
20742            .get(&type_id)
20743            .and_then(|item| item.to_any().downcast_ref::<T>())
20744    }
20745
20746    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20747        let type_id = std::any::TypeId::of::<T>();
20748        self.addons
20749            .get_mut(&type_id)
20750            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20751    }
20752
20753    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20754        let text_layout_details = self.text_layout_details(window);
20755        let style = &text_layout_details.editor_style;
20756        let font_id = window.text_system().resolve_font(&style.text.font());
20757        let font_size = style.text.font_size.to_pixels(window.rem_size());
20758        let line_height = style.text.line_height_in_pixels(window.rem_size());
20759        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20760        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20761
20762        CharacterDimensions {
20763            em_width,
20764            em_advance,
20765            line_height,
20766        }
20767    }
20768
20769    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20770        self.load_diff_task.clone()
20771    }
20772
20773    fn read_metadata_from_db(
20774        &mut self,
20775        item_id: u64,
20776        workspace_id: WorkspaceId,
20777        window: &mut Window,
20778        cx: &mut Context<Editor>,
20779    ) {
20780        if self.is_singleton(cx)
20781            && !self.mode.is_minimap()
20782            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20783        {
20784            let buffer_snapshot = OnceCell::new();
20785
20786            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20787                if !folds.is_empty() {
20788                    let snapshot =
20789                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20790                    self.fold_ranges(
20791                        folds
20792                            .into_iter()
20793                            .map(|(start, end)| {
20794                                snapshot.clip_offset(start, Bias::Left)
20795                                    ..snapshot.clip_offset(end, Bias::Right)
20796                            })
20797                            .collect(),
20798                        false,
20799                        window,
20800                        cx,
20801                    );
20802                }
20803            }
20804
20805            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20806                if !selections.is_empty() {
20807                    let snapshot =
20808                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20809                    // skip adding the initial selection to selection history
20810                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20811                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20812                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20813                            snapshot.clip_offset(start, Bias::Left)
20814                                ..snapshot.clip_offset(end, Bias::Right)
20815                        }));
20816                    });
20817                    self.selection_history.mode = SelectionHistoryMode::Normal;
20818                }
20819            };
20820        }
20821
20822        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20823    }
20824
20825    fn update_lsp_data(
20826        &mut self,
20827        ignore_cache: bool,
20828        for_buffer: Option<BufferId>,
20829        window: &mut Window,
20830        cx: &mut Context<'_, Self>,
20831    ) {
20832        self.pull_diagnostics(for_buffer, window, cx);
20833        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20834    }
20835}
20836
20837fn vim_enabled(cx: &App) -> bool {
20838    cx.global::<SettingsStore>()
20839        .raw_user_settings()
20840        .get("vim_mode")
20841        == Some(&serde_json::Value::Bool(true))
20842}
20843
20844fn process_completion_for_edit(
20845    completion: &Completion,
20846    intent: CompletionIntent,
20847    buffer: &Entity<Buffer>,
20848    cursor_position: &text::Anchor,
20849    cx: &mut Context<Editor>,
20850) -> CompletionEdit {
20851    let buffer = buffer.read(cx);
20852    let buffer_snapshot = buffer.snapshot();
20853    let (snippet, new_text) = if completion.is_snippet() {
20854        // Workaround for typescript language server issues so that methods don't expand within
20855        // strings and functions with type expressions. The previous point is used because the query
20856        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20857        let mut snippet_source = completion.new_text.clone();
20858        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20859        previous_point.column = previous_point.column.saturating_sub(1);
20860        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20861            if scope.prefers_label_for_snippet_in_completion() {
20862                if let Some(label) = completion.label() {
20863                    if matches!(
20864                        completion.kind(),
20865                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20866                    ) {
20867                        snippet_source = label;
20868                    }
20869                }
20870            }
20871        }
20872        match Snippet::parse(&snippet_source).log_err() {
20873            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20874            None => (None, completion.new_text.clone()),
20875        }
20876    } else {
20877        (None, completion.new_text.clone())
20878    };
20879
20880    let mut range_to_replace = {
20881        let replace_range = &completion.replace_range;
20882        if let CompletionSource::Lsp {
20883            insert_range: Some(insert_range),
20884            ..
20885        } = &completion.source
20886        {
20887            debug_assert_eq!(
20888                insert_range.start, replace_range.start,
20889                "insert_range and replace_range should start at the same position"
20890            );
20891            debug_assert!(
20892                insert_range
20893                    .start
20894                    .cmp(&cursor_position, &buffer_snapshot)
20895                    .is_le(),
20896                "insert_range should start before or at cursor position"
20897            );
20898            debug_assert!(
20899                replace_range
20900                    .start
20901                    .cmp(&cursor_position, &buffer_snapshot)
20902                    .is_le(),
20903                "replace_range should start before or at cursor position"
20904            );
20905            debug_assert!(
20906                insert_range
20907                    .end
20908                    .cmp(&cursor_position, &buffer_snapshot)
20909                    .is_le(),
20910                "insert_range should end before or at cursor position"
20911            );
20912
20913            let should_replace = match intent {
20914                CompletionIntent::CompleteWithInsert => false,
20915                CompletionIntent::CompleteWithReplace => true,
20916                CompletionIntent::Complete | CompletionIntent::Compose => {
20917                    let insert_mode =
20918                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20919                            .completions
20920                            .lsp_insert_mode;
20921                    match insert_mode {
20922                        LspInsertMode::Insert => false,
20923                        LspInsertMode::Replace => true,
20924                        LspInsertMode::ReplaceSubsequence => {
20925                            let mut text_to_replace = buffer.chars_for_range(
20926                                buffer.anchor_before(replace_range.start)
20927                                    ..buffer.anchor_after(replace_range.end),
20928                            );
20929                            let mut current_needle = text_to_replace.next();
20930                            for haystack_ch in completion.label.text.chars() {
20931                                if let Some(needle_ch) = current_needle {
20932                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20933                                        current_needle = text_to_replace.next();
20934                                    }
20935                                }
20936                            }
20937                            current_needle.is_none()
20938                        }
20939                        LspInsertMode::ReplaceSuffix => {
20940                            if replace_range
20941                                .end
20942                                .cmp(&cursor_position, &buffer_snapshot)
20943                                .is_gt()
20944                            {
20945                                let range_after_cursor = *cursor_position..replace_range.end;
20946                                let text_after_cursor = buffer
20947                                    .text_for_range(
20948                                        buffer.anchor_before(range_after_cursor.start)
20949                                            ..buffer.anchor_after(range_after_cursor.end),
20950                                    )
20951                                    .collect::<String>()
20952                                    .to_ascii_lowercase();
20953                                completion
20954                                    .label
20955                                    .text
20956                                    .to_ascii_lowercase()
20957                                    .ends_with(&text_after_cursor)
20958                            } else {
20959                                true
20960                            }
20961                        }
20962                    }
20963                }
20964            };
20965
20966            if should_replace {
20967                replace_range.clone()
20968            } else {
20969                insert_range.clone()
20970            }
20971        } else {
20972            replace_range.clone()
20973        }
20974    };
20975
20976    if range_to_replace
20977        .end
20978        .cmp(&cursor_position, &buffer_snapshot)
20979        .is_lt()
20980    {
20981        range_to_replace.end = *cursor_position;
20982    }
20983
20984    CompletionEdit {
20985        new_text,
20986        replace_range: range_to_replace.to_offset(&buffer),
20987        snippet,
20988    }
20989}
20990
20991struct CompletionEdit {
20992    new_text: String,
20993    replace_range: Range<usize>,
20994    snippet: Option<Snippet>,
20995}
20996
20997fn insert_extra_newline_brackets(
20998    buffer: &MultiBufferSnapshot,
20999    range: Range<usize>,
21000    language: &language::LanguageScope,
21001) -> bool {
21002    let leading_whitespace_len = buffer
21003        .reversed_chars_at(range.start)
21004        .take_while(|c| c.is_whitespace() && *c != '\n')
21005        .map(|c| c.len_utf8())
21006        .sum::<usize>();
21007    let trailing_whitespace_len = buffer
21008        .chars_at(range.end)
21009        .take_while(|c| c.is_whitespace() && *c != '\n')
21010        .map(|c| c.len_utf8())
21011        .sum::<usize>();
21012    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21013
21014    language.brackets().any(|(pair, enabled)| {
21015        let pair_start = pair.start.trim_end();
21016        let pair_end = pair.end.trim_start();
21017
21018        enabled
21019            && pair.newline
21020            && buffer.contains_str_at(range.end, pair_end)
21021            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21022    })
21023}
21024
21025fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21026    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21027        [(buffer, range, _)] => (*buffer, range.clone()),
21028        _ => return false,
21029    };
21030    let pair = {
21031        let mut result: Option<BracketMatch> = None;
21032
21033        for pair in buffer
21034            .all_bracket_ranges(range.clone())
21035            .filter(move |pair| {
21036                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21037            })
21038        {
21039            let len = pair.close_range.end - pair.open_range.start;
21040
21041            if let Some(existing) = &result {
21042                let existing_len = existing.close_range.end - existing.open_range.start;
21043                if len > existing_len {
21044                    continue;
21045                }
21046            }
21047
21048            result = Some(pair);
21049        }
21050
21051        result
21052    };
21053    let Some(pair) = pair else {
21054        return false;
21055    };
21056    pair.newline_only
21057        && buffer
21058            .chars_for_range(pair.open_range.end..range.start)
21059            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21060            .all(|c| c.is_whitespace() && c != '\n')
21061}
21062
21063fn update_uncommitted_diff_for_buffer(
21064    editor: Entity<Editor>,
21065    project: &Entity<Project>,
21066    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21067    buffer: Entity<MultiBuffer>,
21068    cx: &mut App,
21069) -> Task<()> {
21070    let mut tasks = Vec::new();
21071    project.update(cx, |project, cx| {
21072        for buffer in buffers {
21073            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21074                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21075            }
21076        }
21077    });
21078    cx.spawn(async move |cx| {
21079        let diffs = future::join_all(tasks).await;
21080        if editor
21081            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21082            .unwrap_or(false)
21083        {
21084            return;
21085        }
21086
21087        buffer
21088            .update(cx, |buffer, cx| {
21089                for diff in diffs.into_iter().flatten() {
21090                    buffer.add_diff(diff, cx);
21091                }
21092            })
21093            .ok();
21094    })
21095}
21096
21097fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21098    let tab_size = tab_size.get() as usize;
21099    let mut width = offset;
21100
21101    for ch in text.chars() {
21102        width += if ch == '\t' {
21103            tab_size - (width % tab_size)
21104        } else {
21105            1
21106        };
21107    }
21108
21109    width - offset
21110}
21111
21112#[cfg(test)]
21113mod tests {
21114    use super::*;
21115
21116    #[test]
21117    fn test_string_size_with_expanded_tabs() {
21118        let nz = |val| NonZeroU32::new(val).unwrap();
21119        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21120        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21121        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21122        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21123        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21124        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21125        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21126        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21127    }
21128}
21129
21130/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21131struct WordBreakingTokenizer<'a> {
21132    input: &'a str,
21133}
21134
21135impl<'a> WordBreakingTokenizer<'a> {
21136    fn new(input: &'a str) -> Self {
21137        Self { input }
21138    }
21139}
21140
21141fn is_char_ideographic(ch: char) -> bool {
21142    use unicode_script::Script::*;
21143    use unicode_script::UnicodeScript;
21144    matches!(ch.script(), Han | Tangut | Yi)
21145}
21146
21147fn is_grapheme_ideographic(text: &str) -> bool {
21148    text.chars().any(is_char_ideographic)
21149}
21150
21151fn is_grapheme_whitespace(text: &str) -> bool {
21152    text.chars().any(|x| x.is_whitespace())
21153}
21154
21155fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21156    text.chars().next().map_or(false, |ch| {
21157        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21158    })
21159}
21160
21161#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21162enum WordBreakToken<'a> {
21163    Word { token: &'a str, grapheme_len: usize },
21164    InlineWhitespace { token: &'a str, grapheme_len: usize },
21165    Newline,
21166}
21167
21168impl<'a> Iterator for WordBreakingTokenizer<'a> {
21169    /// Yields a span, the count of graphemes in the token, and whether it was
21170    /// whitespace. Note that it also breaks at word boundaries.
21171    type Item = WordBreakToken<'a>;
21172
21173    fn next(&mut self) -> Option<Self::Item> {
21174        use unicode_segmentation::UnicodeSegmentation;
21175        if self.input.is_empty() {
21176            return None;
21177        }
21178
21179        let mut iter = self.input.graphemes(true).peekable();
21180        let mut offset = 0;
21181        let mut grapheme_len = 0;
21182        if let Some(first_grapheme) = iter.next() {
21183            let is_newline = first_grapheme == "\n";
21184            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21185            offset += first_grapheme.len();
21186            grapheme_len += 1;
21187            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21188                if let Some(grapheme) = iter.peek().copied() {
21189                    if should_stay_with_preceding_ideograph(grapheme) {
21190                        offset += grapheme.len();
21191                        grapheme_len += 1;
21192                    }
21193                }
21194            } else {
21195                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21196                let mut next_word_bound = words.peek().copied();
21197                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21198                    next_word_bound = words.next();
21199                }
21200                while let Some(grapheme) = iter.peek().copied() {
21201                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21202                        break;
21203                    };
21204                    if is_grapheme_whitespace(grapheme) != is_whitespace
21205                        || (grapheme == "\n") != is_newline
21206                    {
21207                        break;
21208                    };
21209                    offset += grapheme.len();
21210                    grapheme_len += 1;
21211                    iter.next();
21212                }
21213            }
21214            let token = &self.input[..offset];
21215            self.input = &self.input[offset..];
21216            if token == "\n" {
21217                Some(WordBreakToken::Newline)
21218            } else if is_whitespace {
21219                Some(WordBreakToken::InlineWhitespace {
21220                    token,
21221                    grapheme_len,
21222                })
21223            } else {
21224                Some(WordBreakToken::Word {
21225                    token,
21226                    grapheme_len,
21227                })
21228            }
21229        } else {
21230            None
21231        }
21232    }
21233}
21234
21235#[test]
21236fn test_word_breaking_tokenizer() {
21237    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21238        ("", &[]),
21239        ("  ", &[whitespace("  ", 2)]),
21240        ("Ʒ", &[word("Ʒ", 1)]),
21241        ("Ǽ", &[word("Ǽ", 1)]),
21242        ("", &[word("", 1)]),
21243        ("⋑⋑", &[word("⋑⋑", 2)]),
21244        (
21245            "原理,进而",
21246            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21247        ),
21248        (
21249            "hello world",
21250            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21251        ),
21252        (
21253            "hello, world",
21254            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21255        ),
21256        (
21257            "  hello world",
21258            &[
21259                whitespace("  ", 2),
21260                word("hello", 5),
21261                whitespace(" ", 1),
21262                word("world", 5),
21263            ],
21264        ),
21265        (
21266            "这是什么 \n 钢笔",
21267            &[
21268                word("", 1),
21269                word("", 1),
21270                word("", 1),
21271                word("", 1),
21272                whitespace(" ", 1),
21273                newline(),
21274                whitespace(" ", 1),
21275                word("", 1),
21276                word("", 1),
21277            ],
21278        ),
21279        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21280    ];
21281
21282    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21283        WordBreakToken::Word {
21284            token,
21285            grapheme_len,
21286        }
21287    }
21288
21289    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21290        WordBreakToken::InlineWhitespace {
21291            token,
21292            grapheme_len,
21293        }
21294    }
21295
21296    fn newline() -> WordBreakToken<'static> {
21297        WordBreakToken::Newline
21298    }
21299
21300    for (input, result) in tests {
21301        assert_eq!(
21302            WordBreakingTokenizer::new(input)
21303                .collect::<Vec<_>>()
21304                .as_slice(),
21305            *result,
21306        );
21307    }
21308}
21309
21310fn wrap_with_prefix(
21311    first_line_prefix: String,
21312    subsequent_lines_prefix: String,
21313    unwrapped_text: String,
21314    wrap_column: usize,
21315    tab_size: NonZeroU32,
21316    preserve_existing_whitespace: bool,
21317) -> String {
21318    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21319    let subsequent_lines_prefix_len =
21320        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21321    let mut wrapped_text = String::new();
21322    let mut current_line = first_line_prefix.clone();
21323    let mut is_first_line = true;
21324
21325    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21326    let mut current_line_len = first_line_prefix_len;
21327    let mut in_whitespace = false;
21328    for token in tokenizer {
21329        let have_preceding_whitespace = in_whitespace;
21330        match token {
21331            WordBreakToken::Word {
21332                token,
21333                grapheme_len,
21334            } => {
21335                in_whitespace = false;
21336                let current_prefix_len = if is_first_line {
21337                    first_line_prefix_len
21338                } else {
21339                    subsequent_lines_prefix_len
21340                };
21341                if current_line_len + grapheme_len > wrap_column
21342                    && current_line_len != current_prefix_len
21343                {
21344                    wrapped_text.push_str(current_line.trim_end());
21345                    wrapped_text.push('\n');
21346                    is_first_line = false;
21347                    current_line = subsequent_lines_prefix.clone();
21348                    current_line_len = subsequent_lines_prefix_len;
21349                }
21350                current_line.push_str(token);
21351                current_line_len += grapheme_len;
21352            }
21353            WordBreakToken::InlineWhitespace {
21354                mut token,
21355                mut grapheme_len,
21356            } => {
21357                in_whitespace = true;
21358                if have_preceding_whitespace && !preserve_existing_whitespace {
21359                    continue;
21360                }
21361                if !preserve_existing_whitespace {
21362                    token = " ";
21363                    grapheme_len = 1;
21364                }
21365                let current_prefix_len = if is_first_line {
21366                    first_line_prefix_len
21367                } else {
21368                    subsequent_lines_prefix_len
21369                };
21370                if current_line_len + grapheme_len > wrap_column {
21371                    wrapped_text.push_str(current_line.trim_end());
21372                    wrapped_text.push('\n');
21373                    is_first_line = false;
21374                    current_line = subsequent_lines_prefix.clone();
21375                    current_line_len = subsequent_lines_prefix_len;
21376                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21377                    current_line.push_str(token);
21378                    current_line_len += grapheme_len;
21379                }
21380            }
21381            WordBreakToken::Newline => {
21382                in_whitespace = true;
21383                let current_prefix_len = if is_first_line {
21384                    first_line_prefix_len
21385                } else {
21386                    subsequent_lines_prefix_len
21387                };
21388                if preserve_existing_whitespace {
21389                    wrapped_text.push_str(current_line.trim_end());
21390                    wrapped_text.push('\n');
21391                    is_first_line = false;
21392                    current_line = subsequent_lines_prefix.clone();
21393                    current_line_len = subsequent_lines_prefix_len;
21394                } else if have_preceding_whitespace {
21395                    continue;
21396                } else if current_line_len + 1 > wrap_column
21397                    && current_line_len != current_prefix_len
21398                {
21399                    wrapped_text.push_str(current_line.trim_end());
21400                    wrapped_text.push('\n');
21401                    is_first_line = false;
21402                    current_line = subsequent_lines_prefix.clone();
21403                    current_line_len = subsequent_lines_prefix_len;
21404                } else if current_line_len != current_prefix_len {
21405                    current_line.push(' ');
21406                    current_line_len += 1;
21407                }
21408            }
21409        }
21410    }
21411
21412    if !current_line.is_empty() {
21413        wrapped_text.push_str(&current_line);
21414    }
21415    wrapped_text
21416}
21417
21418#[test]
21419fn test_wrap_with_prefix() {
21420    assert_eq!(
21421        wrap_with_prefix(
21422            "# ".to_string(),
21423            "# ".to_string(),
21424            "abcdefg".to_string(),
21425            4,
21426            NonZeroU32::new(4).unwrap(),
21427            false,
21428        ),
21429        "# abcdefg"
21430    );
21431    assert_eq!(
21432        wrap_with_prefix(
21433            "".to_string(),
21434            "".to_string(),
21435            "\thello world".to_string(),
21436            8,
21437            NonZeroU32::new(4).unwrap(),
21438            false,
21439        ),
21440        "hello\nworld"
21441    );
21442    assert_eq!(
21443        wrap_with_prefix(
21444            "// ".to_string(),
21445            "// ".to_string(),
21446            "xx \nyy zz aa bb cc".to_string(),
21447            12,
21448            NonZeroU32::new(4).unwrap(),
21449            false,
21450        ),
21451        "// xx yy zz\n// aa bb cc"
21452    );
21453    assert_eq!(
21454        wrap_with_prefix(
21455            String::new(),
21456            String::new(),
21457            "这是什么 \n 钢笔".to_string(),
21458            3,
21459            NonZeroU32::new(4).unwrap(),
21460            false,
21461        ),
21462        "这是什\n么 钢\n"
21463    );
21464}
21465
21466pub trait CollaborationHub {
21467    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21468    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21469    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21470}
21471
21472impl CollaborationHub for Entity<Project> {
21473    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21474        self.read(cx).collaborators()
21475    }
21476
21477    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21478        self.read(cx).user_store().read(cx).participant_indices()
21479    }
21480
21481    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21482        let this = self.read(cx);
21483        let user_ids = this.collaborators().values().map(|c| c.user_id);
21484        this.user_store().read(cx).participant_names(user_ids, cx)
21485    }
21486}
21487
21488pub trait SemanticsProvider {
21489    fn hover(
21490        &self,
21491        buffer: &Entity<Buffer>,
21492        position: text::Anchor,
21493        cx: &mut App,
21494    ) -> Option<Task<Vec<project::Hover>>>;
21495
21496    fn inline_values(
21497        &self,
21498        buffer_handle: Entity<Buffer>,
21499        range: Range<text::Anchor>,
21500        cx: &mut App,
21501    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21502
21503    fn inlay_hints(
21504        &self,
21505        buffer_handle: Entity<Buffer>,
21506        range: Range<text::Anchor>,
21507        cx: &mut App,
21508    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21509
21510    fn resolve_inlay_hint(
21511        &self,
21512        hint: InlayHint,
21513        buffer_handle: Entity<Buffer>,
21514        server_id: LanguageServerId,
21515        cx: &mut App,
21516    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21517
21518    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21519
21520    fn document_highlights(
21521        &self,
21522        buffer: &Entity<Buffer>,
21523        position: text::Anchor,
21524        cx: &mut App,
21525    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21526
21527    fn definitions(
21528        &self,
21529        buffer: &Entity<Buffer>,
21530        position: text::Anchor,
21531        kind: GotoDefinitionKind,
21532        cx: &mut App,
21533    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21534
21535    fn range_for_rename(
21536        &self,
21537        buffer: &Entity<Buffer>,
21538        position: text::Anchor,
21539        cx: &mut App,
21540    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21541
21542    fn perform_rename(
21543        &self,
21544        buffer: &Entity<Buffer>,
21545        position: text::Anchor,
21546        new_name: String,
21547        cx: &mut App,
21548    ) -> Option<Task<Result<ProjectTransaction>>>;
21549}
21550
21551pub trait CompletionProvider {
21552    fn completions(
21553        &self,
21554        excerpt_id: ExcerptId,
21555        buffer: &Entity<Buffer>,
21556        buffer_position: text::Anchor,
21557        trigger: CompletionContext,
21558        window: &mut Window,
21559        cx: &mut Context<Editor>,
21560    ) -> Task<Result<Vec<CompletionResponse>>>;
21561
21562    fn resolve_completions(
21563        &self,
21564        _buffer: Entity<Buffer>,
21565        _completion_indices: Vec<usize>,
21566        _completions: Rc<RefCell<Box<[Completion]>>>,
21567        _cx: &mut Context<Editor>,
21568    ) -> Task<Result<bool>> {
21569        Task::ready(Ok(false))
21570    }
21571
21572    fn apply_additional_edits_for_completion(
21573        &self,
21574        _buffer: Entity<Buffer>,
21575        _completions: Rc<RefCell<Box<[Completion]>>>,
21576        _completion_index: usize,
21577        _push_to_history: bool,
21578        _cx: &mut Context<Editor>,
21579    ) -> Task<Result<Option<language::Transaction>>> {
21580        Task::ready(Ok(None))
21581    }
21582
21583    fn is_completion_trigger(
21584        &self,
21585        buffer: &Entity<Buffer>,
21586        position: language::Anchor,
21587        text: &str,
21588        trigger_in_words: bool,
21589        menu_is_open: bool,
21590        cx: &mut Context<Editor>,
21591    ) -> bool;
21592
21593    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21594
21595    fn sort_completions(&self) -> bool {
21596        true
21597    }
21598
21599    fn filter_completions(&self) -> bool {
21600        true
21601    }
21602}
21603
21604pub trait CodeActionProvider {
21605    fn id(&self) -> Arc<str>;
21606
21607    fn code_actions(
21608        &self,
21609        buffer: &Entity<Buffer>,
21610        range: Range<text::Anchor>,
21611        window: &mut Window,
21612        cx: &mut App,
21613    ) -> Task<Result<Vec<CodeAction>>>;
21614
21615    fn apply_code_action(
21616        &self,
21617        buffer_handle: Entity<Buffer>,
21618        action: CodeAction,
21619        excerpt_id: ExcerptId,
21620        push_to_history: bool,
21621        window: &mut Window,
21622        cx: &mut App,
21623    ) -> Task<Result<ProjectTransaction>>;
21624}
21625
21626impl CodeActionProvider for Entity<Project> {
21627    fn id(&self) -> Arc<str> {
21628        "project".into()
21629    }
21630
21631    fn code_actions(
21632        &self,
21633        buffer: &Entity<Buffer>,
21634        range: Range<text::Anchor>,
21635        _window: &mut Window,
21636        cx: &mut App,
21637    ) -> Task<Result<Vec<CodeAction>>> {
21638        self.update(cx, |project, cx| {
21639            let code_lens = project.code_lens(buffer, range.clone(), cx);
21640            let code_actions = project.code_actions(buffer, range, None, cx);
21641            cx.background_spawn(async move {
21642                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21643                Ok(code_lens
21644                    .context("code lens fetch")?
21645                    .into_iter()
21646                    .chain(code_actions.context("code action fetch")?)
21647                    .collect())
21648            })
21649        })
21650    }
21651
21652    fn apply_code_action(
21653        &self,
21654        buffer_handle: Entity<Buffer>,
21655        action: CodeAction,
21656        _excerpt_id: ExcerptId,
21657        push_to_history: bool,
21658        _window: &mut Window,
21659        cx: &mut App,
21660    ) -> Task<Result<ProjectTransaction>> {
21661        self.update(cx, |project, cx| {
21662            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21663        })
21664    }
21665}
21666
21667fn snippet_completions(
21668    project: &Project,
21669    buffer: &Entity<Buffer>,
21670    buffer_position: text::Anchor,
21671    cx: &mut App,
21672) -> Task<Result<CompletionResponse>> {
21673    let languages = buffer.read(cx).languages_at(buffer_position);
21674    let snippet_store = project.snippets().read(cx);
21675
21676    let scopes: Vec<_> = languages
21677        .iter()
21678        .filter_map(|language| {
21679            let language_name = language.lsp_id();
21680            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21681
21682            if snippets.is_empty() {
21683                None
21684            } else {
21685                Some((language.default_scope(), snippets))
21686            }
21687        })
21688        .collect();
21689
21690    if scopes.is_empty() {
21691        return Task::ready(Ok(CompletionResponse {
21692            completions: vec![],
21693            is_incomplete: false,
21694        }));
21695    }
21696
21697    let snapshot = buffer.read(cx).text_snapshot();
21698    let chars: String = snapshot
21699        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21700        .collect();
21701    let executor = cx.background_executor().clone();
21702
21703    cx.background_spawn(async move {
21704        let mut is_incomplete = false;
21705        let mut completions: Vec<Completion> = Vec::new();
21706        for (scope, snippets) in scopes.into_iter() {
21707            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21708            let mut last_word = chars
21709                .chars()
21710                .take_while(|c| classifier.is_word(*c))
21711                .collect::<String>();
21712            last_word = last_word.chars().rev().collect();
21713
21714            if last_word.is_empty() {
21715                return Ok(CompletionResponse {
21716                    completions: vec![],
21717                    is_incomplete: true,
21718                });
21719            }
21720
21721            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21722            let to_lsp = |point: &text::Anchor| {
21723                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21724                point_to_lsp(end)
21725            };
21726            let lsp_end = to_lsp(&buffer_position);
21727
21728            let candidates = snippets
21729                .iter()
21730                .enumerate()
21731                .flat_map(|(ix, snippet)| {
21732                    snippet
21733                        .prefix
21734                        .iter()
21735                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21736                })
21737                .collect::<Vec<StringMatchCandidate>>();
21738
21739            const MAX_RESULTS: usize = 100;
21740            let mut matches = fuzzy::match_strings(
21741                &candidates,
21742                &last_word,
21743                last_word.chars().any(|c| c.is_uppercase()),
21744                true,
21745                MAX_RESULTS,
21746                &Default::default(),
21747                executor.clone(),
21748            )
21749            .await;
21750
21751            if matches.len() >= MAX_RESULTS {
21752                is_incomplete = true;
21753            }
21754
21755            // Remove all candidates where the query's start does not match the start of any word in the candidate
21756            if let Some(query_start) = last_word.chars().next() {
21757                matches.retain(|string_match| {
21758                    split_words(&string_match.string).any(|word| {
21759                        // Check that the first codepoint of the word as lowercase matches the first
21760                        // codepoint of the query as lowercase
21761                        word.chars()
21762                            .flat_map(|codepoint| codepoint.to_lowercase())
21763                            .zip(query_start.to_lowercase())
21764                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21765                    })
21766                });
21767            }
21768
21769            let matched_strings = matches
21770                .into_iter()
21771                .map(|m| m.string)
21772                .collect::<HashSet<_>>();
21773
21774            completions.extend(snippets.iter().filter_map(|snippet| {
21775                let matching_prefix = snippet
21776                    .prefix
21777                    .iter()
21778                    .find(|prefix| matched_strings.contains(*prefix))?;
21779                let start = as_offset - last_word.len();
21780                let start = snapshot.anchor_before(start);
21781                let range = start..buffer_position;
21782                let lsp_start = to_lsp(&start);
21783                let lsp_range = lsp::Range {
21784                    start: lsp_start,
21785                    end: lsp_end,
21786                };
21787                Some(Completion {
21788                    replace_range: range,
21789                    new_text: snippet.body.clone(),
21790                    source: CompletionSource::Lsp {
21791                        insert_range: None,
21792                        server_id: LanguageServerId(usize::MAX),
21793                        resolved: true,
21794                        lsp_completion: Box::new(lsp::CompletionItem {
21795                            label: snippet.prefix.first().unwrap().clone(),
21796                            kind: Some(CompletionItemKind::SNIPPET),
21797                            label_details: snippet.description.as_ref().map(|description| {
21798                                lsp::CompletionItemLabelDetails {
21799                                    detail: Some(description.clone()),
21800                                    description: None,
21801                                }
21802                            }),
21803                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21804                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21805                                lsp::InsertReplaceEdit {
21806                                    new_text: snippet.body.clone(),
21807                                    insert: lsp_range,
21808                                    replace: lsp_range,
21809                                },
21810                            )),
21811                            filter_text: Some(snippet.body.clone()),
21812                            sort_text: Some(char::MAX.to_string()),
21813                            ..lsp::CompletionItem::default()
21814                        }),
21815                        lsp_defaults: None,
21816                    },
21817                    label: CodeLabel {
21818                        text: matching_prefix.clone(),
21819                        runs: Vec::new(),
21820                        filter_range: 0..matching_prefix.len(),
21821                    },
21822                    icon_path: None,
21823                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21824                        single_line: snippet.name.clone().into(),
21825                        plain_text: snippet
21826                            .description
21827                            .clone()
21828                            .map(|description| description.into()),
21829                    }),
21830                    insert_text_mode: None,
21831                    confirm: None,
21832                })
21833            }))
21834        }
21835
21836        Ok(CompletionResponse {
21837            completions,
21838            is_incomplete,
21839        })
21840    })
21841}
21842
21843impl CompletionProvider for Entity<Project> {
21844    fn completions(
21845        &self,
21846        _excerpt_id: ExcerptId,
21847        buffer: &Entity<Buffer>,
21848        buffer_position: text::Anchor,
21849        options: CompletionContext,
21850        _window: &mut Window,
21851        cx: &mut Context<Editor>,
21852    ) -> Task<Result<Vec<CompletionResponse>>> {
21853        self.update(cx, |project, cx| {
21854            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21855            let project_completions = project.completions(buffer, buffer_position, options, cx);
21856            cx.background_spawn(async move {
21857                let mut responses = project_completions.await?;
21858                let snippets = snippets.await?;
21859                if !snippets.completions.is_empty() {
21860                    responses.push(snippets);
21861                }
21862                Ok(responses)
21863            })
21864        })
21865    }
21866
21867    fn resolve_completions(
21868        &self,
21869        buffer: Entity<Buffer>,
21870        completion_indices: Vec<usize>,
21871        completions: Rc<RefCell<Box<[Completion]>>>,
21872        cx: &mut Context<Editor>,
21873    ) -> Task<Result<bool>> {
21874        self.update(cx, |project, cx| {
21875            project.lsp_store().update(cx, |lsp_store, cx| {
21876                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21877            })
21878        })
21879    }
21880
21881    fn apply_additional_edits_for_completion(
21882        &self,
21883        buffer: Entity<Buffer>,
21884        completions: Rc<RefCell<Box<[Completion]>>>,
21885        completion_index: usize,
21886        push_to_history: bool,
21887        cx: &mut Context<Editor>,
21888    ) -> Task<Result<Option<language::Transaction>>> {
21889        self.update(cx, |project, cx| {
21890            project.lsp_store().update(cx, |lsp_store, cx| {
21891                lsp_store.apply_additional_edits_for_completion(
21892                    buffer,
21893                    completions,
21894                    completion_index,
21895                    push_to_history,
21896                    cx,
21897                )
21898            })
21899        })
21900    }
21901
21902    fn is_completion_trigger(
21903        &self,
21904        buffer: &Entity<Buffer>,
21905        position: language::Anchor,
21906        text: &str,
21907        trigger_in_words: bool,
21908        menu_is_open: bool,
21909        cx: &mut Context<Editor>,
21910    ) -> bool {
21911        let mut chars = text.chars();
21912        let char = if let Some(char) = chars.next() {
21913            char
21914        } else {
21915            return false;
21916        };
21917        if chars.next().is_some() {
21918            return false;
21919        }
21920
21921        let buffer = buffer.read(cx);
21922        let snapshot = buffer.snapshot();
21923        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21924            return false;
21925        }
21926        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21927        if trigger_in_words && classifier.is_word(char) {
21928            return true;
21929        }
21930
21931        buffer.completion_triggers().contains(text)
21932    }
21933}
21934
21935impl SemanticsProvider for Entity<Project> {
21936    fn hover(
21937        &self,
21938        buffer: &Entity<Buffer>,
21939        position: text::Anchor,
21940        cx: &mut App,
21941    ) -> Option<Task<Vec<project::Hover>>> {
21942        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21943    }
21944
21945    fn document_highlights(
21946        &self,
21947        buffer: &Entity<Buffer>,
21948        position: text::Anchor,
21949        cx: &mut App,
21950    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21951        Some(self.update(cx, |project, cx| {
21952            project.document_highlights(buffer, position, cx)
21953        }))
21954    }
21955
21956    fn definitions(
21957        &self,
21958        buffer: &Entity<Buffer>,
21959        position: text::Anchor,
21960        kind: GotoDefinitionKind,
21961        cx: &mut App,
21962    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21963        Some(self.update(cx, |project, cx| match kind {
21964            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
21965            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
21966            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
21967            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
21968        }))
21969    }
21970
21971    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21972        // TODO: make this work for remote projects
21973        self.update(cx, |project, cx| {
21974            if project
21975                .active_debug_session(cx)
21976                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21977            {
21978                return true;
21979            }
21980
21981            buffer.update(cx, |buffer, cx| {
21982                project.any_language_server_supports_inlay_hints(buffer, cx)
21983            })
21984        })
21985    }
21986
21987    fn inline_values(
21988        &self,
21989        buffer_handle: Entity<Buffer>,
21990        range: Range<text::Anchor>,
21991        cx: &mut App,
21992    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21993        self.update(cx, |project, cx| {
21994            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21995
21996            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21997        })
21998    }
21999
22000    fn inlay_hints(
22001        &self,
22002        buffer_handle: Entity<Buffer>,
22003        range: Range<text::Anchor>,
22004        cx: &mut App,
22005    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22006        Some(self.update(cx, |project, cx| {
22007            project.inlay_hints(buffer_handle, range, cx)
22008        }))
22009    }
22010
22011    fn resolve_inlay_hint(
22012        &self,
22013        hint: InlayHint,
22014        buffer_handle: Entity<Buffer>,
22015        server_id: LanguageServerId,
22016        cx: &mut App,
22017    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22018        Some(self.update(cx, |project, cx| {
22019            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22020        }))
22021    }
22022
22023    fn range_for_rename(
22024        &self,
22025        buffer: &Entity<Buffer>,
22026        position: text::Anchor,
22027        cx: &mut App,
22028    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22029        Some(self.update(cx, |project, cx| {
22030            let buffer = buffer.clone();
22031            let task = project.prepare_rename(buffer.clone(), position, cx);
22032            cx.spawn(async move |_, cx| {
22033                Ok(match task.await? {
22034                    PrepareRenameResponse::Success(range) => Some(range),
22035                    PrepareRenameResponse::InvalidPosition => None,
22036                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22037                        // Fallback on using TreeSitter info to determine identifier range
22038                        buffer.read_with(cx, |buffer, _| {
22039                            let snapshot = buffer.snapshot();
22040                            let (range, kind) = snapshot.surrounding_word(position);
22041                            if kind != Some(CharKind::Word) {
22042                                return None;
22043                            }
22044                            Some(
22045                                snapshot.anchor_before(range.start)
22046                                    ..snapshot.anchor_after(range.end),
22047                            )
22048                        })?
22049                    }
22050                })
22051            })
22052        }))
22053    }
22054
22055    fn perform_rename(
22056        &self,
22057        buffer: &Entity<Buffer>,
22058        position: text::Anchor,
22059        new_name: String,
22060        cx: &mut App,
22061    ) -> Option<Task<Result<ProjectTransaction>>> {
22062        Some(self.update(cx, |project, cx| {
22063            project.perform_rename(buffer.clone(), position, new_name, cx)
22064        }))
22065    }
22066}
22067
22068fn inlay_hint_settings(
22069    location: Anchor,
22070    snapshot: &MultiBufferSnapshot,
22071    cx: &mut Context<Editor>,
22072) -> InlayHintSettings {
22073    let file = snapshot.file_at(location);
22074    let language = snapshot.language_at(location).map(|l| l.name());
22075    language_settings(language, file, cx).inlay_hints
22076}
22077
22078fn consume_contiguous_rows(
22079    contiguous_row_selections: &mut Vec<Selection<Point>>,
22080    selection: &Selection<Point>,
22081    display_map: &DisplaySnapshot,
22082    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22083) -> (MultiBufferRow, MultiBufferRow) {
22084    contiguous_row_selections.push(selection.clone());
22085    let start_row = MultiBufferRow(selection.start.row);
22086    let mut end_row = ending_row(selection, display_map);
22087
22088    while let Some(next_selection) = selections.peek() {
22089        if next_selection.start.row <= end_row.0 {
22090            end_row = ending_row(next_selection, display_map);
22091            contiguous_row_selections.push(selections.next().unwrap().clone());
22092        } else {
22093            break;
22094        }
22095    }
22096    (start_row, end_row)
22097}
22098
22099fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22100    if next_selection.end.column > 0 || next_selection.is_empty() {
22101        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22102    } else {
22103        MultiBufferRow(next_selection.end.row)
22104    }
22105}
22106
22107impl EditorSnapshot {
22108    pub fn remote_selections_in_range<'a>(
22109        &'a self,
22110        range: &'a Range<Anchor>,
22111        collaboration_hub: &dyn CollaborationHub,
22112        cx: &'a App,
22113    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22114        let participant_names = collaboration_hub.user_names(cx);
22115        let participant_indices = collaboration_hub.user_participant_indices(cx);
22116        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22117        let collaborators_by_replica_id = collaborators_by_peer_id
22118            .values()
22119            .map(|collaborator| (collaborator.replica_id, collaborator))
22120            .collect::<HashMap<_, _>>();
22121        self.buffer_snapshot
22122            .selections_in_range(range, false)
22123            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22124                if replica_id == AGENT_REPLICA_ID {
22125                    Some(RemoteSelection {
22126                        replica_id,
22127                        selection,
22128                        cursor_shape,
22129                        line_mode,
22130                        collaborator_id: CollaboratorId::Agent,
22131                        user_name: Some("Agent".into()),
22132                        color: cx.theme().players().agent(),
22133                    })
22134                } else {
22135                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22136                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22137                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22138                    Some(RemoteSelection {
22139                        replica_id,
22140                        selection,
22141                        cursor_shape,
22142                        line_mode,
22143                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22144                        user_name,
22145                        color: if let Some(index) = participant_index {
22146                            cx.theme().players().color_for_participant(index.0)
22147                        } else {
22148                            cx.theme().players().absent()
22149                        },
22150                    })
22151                }
22152            })
22153    }
22154
22155    pub fn hunks_for_ranges(
22156        &self,
22157        ranges: impl IntoIterator<Item = Range<Point>>,
22158    ) -> Vec<MultiBufferDiffHunk> {
22159        let mut hunks = Vec::new();
22160        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22161            HashMap::default();
22162        for query_range in ranges {
22163            let query_rows =
22164                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22165            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22166                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22167            ) {
22168                // Include deleted hunks that are adjacent to the query range, because
22169                // otherwise they would be missed.
22170                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22171                if hunk.status().is_deleted() {
22172                    intersects_range |= hunk.row_range.start == query_rows.end;
22173                    intersects_range |= hunk.row_range.end == query_rows.start;
22174                }
22175                if intersects_range {
22176                    if !processed_buffer_rows
22177                        .entry(hunk.buffer_id)
22178                        .or_default()
22179                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22180                    {
22181                        continue;
22182                    }
22183                    hunks.push(hunk);
22184                }
22185            }
22186        }
22187
22188        hunks
22189    }
22190
22191    fn display_diff_hunks_for_rows<'a>(
22192        &'a self,
22193        display_rows: Range<DisplayRow>,
22194        folded_buffers: &'a HashSet<BufferId>,
22195    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22196        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22197        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22198
22199        self.buffer_snapshot
22200            .diff_hunks_in_range(buffer_start..buffer_end)
22201            .filter_map(|hunk| {
22202                if folded_buffers.contains(&hunk.buffer_id) {
22203                    return None;
22204                }
22205
22206                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22207                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22208
22209                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22210                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22211
22212                let display_hunk = if hunk_display_start.column() != 0 {
22213                    DisplayDiffHunk::Folded {
22214                        display_row: hunk_display_start.row(),
22215                    }
22216                } else {
22217                    let mut end_row = hunk_display_end.row();
22218                    if hunk_display_end.column() > 0 {
22219                        end_row.0 += 1;
22220                    }
22221                    let is_created_file = hunk.is_created_file();
22222                    DisplayDiffHunk::Unfolded {
22223                        status: hunk.status(),
22224                        diff_base_byte_range: hunk.diff_base_byte_range,
22225                        display_row_range: hunk_display_start.row()..end_row,
22226                        multi_buffer_range: Anchor::range_in_buffer(
22227                            hunk.excerpt_id,
22228                            hunk.buffer_id,
22229                            hunk.buffer_range,
22230                        ),
22231                        is_created_file,
22232                    }
22233                };
22234
22235                Some(display_hunk)
22236            })
22237    }
22238
22239    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22240        self.display_snapshot.buffer_snapshot.language_at(position)
22241    }
22242
22243    pub fn is_focused(&self) -> bool {
22244        self.is_focused
22245    }
22246
22247    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22248        self.placeholder_text.as_ref()
22249    }
22250
22251    pub fn scroll_position(&self) -> gpui::Point<f32> {
22252        self.scroll_anchor.scroll_position(&self.display_snapshot)
22253    }
22254
22255    fn gutter_dimensions(
22256        &self,
22257        font_id: FontId,
22258        font_size: Pixels,
22259        max_line_number_width: Pixels,
22260        cx: &App,
22261    ) -> Option<GutterDimensions> {
22262        if !self.show_gutter {
22263            return None;
22264        }
22265
22266        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22267        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22268
22269        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22270            matches!(
22271                ProjectSettings::get_global(cx).git.git_gutter,
22272                Some(GitGutterSetting::TrackedFiles)
22273            )
22274        });
22275        let gutter_settings = EditorSettings::get_global(cx).gutter;
22276        let show_line_numbers = self
22277            .show_line_numbers
22278            .unwrap_or(gutter_settings.line_numbers);
22279        let line_gutter_width = if show_line_numbers {
22280            // Avoid flicker-like gutter resizes when the line number gains another digit by
22281            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22282            let min_width_for_number_on_gutter =
22283                ch_advance * gutter_settings.min_line_number_digits as f32;
22284            max_line_number_width.max(min_width_for_number_on_gutter)
22285        } else {
22286            0.0.into()
22287        };
22288
22289        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22290        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22291
22292        let git_blame_entries_width =
22293            self.git_blame_gutter_max_author_length
22294                .map(|max_author_length| {
22295                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22296                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22297
22298                    /// The number of characters to dedicate to gaps and margins.
22299                    const SPACING_WIDTH: usize = 4;
22300
22301                    let max_char_count = max_author_length.min(renderer.max_author_length())
22302                        + ::git::SHORT_SHA_LENGTH
22303                        + MAX_RELATIVE_TIMESTAMP.len()
22304                        + SPACING_WIDTH;
22305
22306                    ch_advance * max_char_count
22307                });
22308
22309        let is_singleton = self.buffer_snapshot.is_singleton();
22310
22311        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22312        left_padding += if !is_singleton {
22313            ch_width * 4.0
22314        } else if show_runnables || show_breakpoints {
22315            ch_width * 3.0
22316        } else if show_git_gutter && show_line_numbers {
22317            ch_width * 2.0
22318        } else if show_git_gutter || show_line_numbers {
22319            ch_width
22320        } else {
22321            px(0.)
22322        };
22323
22324        let shows_folds = is_singleton && gutter_settings.folds;
22325
22326        let right_padding = if shows_folds && show_line_numbers {
22327            ch_width * 4.0
22328        } else if shows_folds || (!is_singleton && show_line_numbers) {
22329            ch_width * 3.0
22330        } else if show_line_numbers {
22331            ch_width
22332        } else {
22333            px(0.)
22334        };
22335
22336        Some(GutterDimensions {
22337            left_padding,
22338            right_padding,
22339            width: line_gutter_width + left_padding + right_padding,
22340            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22341            git_blame_entries_width,
22342        })
22343    }
22344
22345    pub fn render_crease_toggle(
22346        &self,
22347        buffer_row: MultiBufferRow,
22348        row_contains_cursor: bool,
22349        editor: Entity<Editor>,
22350        window: &mut Window,
22351        cx: &mut App,
22352    ) -> Option<AnyElement> {
22353        let folded = self.is_line_folded(buffer_row);
22354        let mut is_foldable = false;
22355
22356        if let Some(crease) = self
22357            .crease_snapshot
22358            .query_row(buffer_row, &self.buffer_snapshot)
22359        {
22360            is_foldable = true;
22361            match crease {
22362                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22363                    if let Some(render_toggle) = render_toggle {
22364                        let toggle_callback =
22365                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22366                                if folded {
22367                                    editor.update(cx, |editor, cx| {
22368                                        editor.fold_at(buffer_row, window, cx)
22369                                    });
22370                                } else {
22371                                    editor.update(cx, |editor, cx| {
22372                                        editor.unfold_at(buffer_row, window, cx)
22373                                    });
22374                                }
22375                            });
22376                        return Some((render_toggle)(
22377                            buffer_row,
22378                            folded,
22379                            toggle_callback,
22380                            window,
22381                            cx,
22382                        ));
22383                    }
22384                }
22385            }
22386        }
22387
22388        is_foldable |= self.starts_indent(buffer_row);
22389
22390        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22391            Some(
22392                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22393                    .toggle_state(folded)
22394                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22395                        if folded {
22396                            this.unfold_at(buffer_row, window, cx);
22397                        } else {
22398                            this.fold_at(buffer_row, window, cx);
22399                        }
22400                    }))
22401                    .into_any_element(),
22402            )
22403        } else {
22404            None
22405        }
22406    }
22407
22408    pub fn render_crease_trailer(
22409        &self,
22410        buffer_row: MultiBufferRow,
22411        window: &mut Window,
22412        cx: &mut App,
22413    ) -> Option<AnyElement> {
22414        let folded = self.is_line_folded(buffer_row);
22415        if let Crease::Inline { render_trailer, .. } = self
22416            .crease_snapshot
22417            .query_row(buffer_row, &self.buffer_snapshot)?
22418        {
22419            let render_trailer = render_trailer.as_ref()?;
22420            Some(render_trailer(buffer_row, folded, window, cx))
22421        } else {
22422            None
22423        }
22424    }
22425}
22426
22427impl Deref for EditorSnapshot {
22428    type Target = DisplaySnapshot;
22429
22430    fn deref(&self) -> &Self::Target {
22431        &self.display_snapshot
22432    }
22433}
22434
22435#[derive(Clone, Debug, PartialEq, Eq)]
22436pub enum EditorEvent {
22437    InputIgnored {
22438        text: Arc<str>,
22439    },
22440    InputHandled {
22441        utf16_range_to_replace: Option<Range<isize>>,
22442        text: Arc<str>,
22443    },
22444    ExcerptsAdded {
22445        buffer: Entity<Buffer>,
22446        predecessor: ExcerptId,
22447        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22448    },
22449    ExcerptsRemoved {
22450        ids: Vec<ExcerptId>,
22451        removed_buffer_ids: Vec<BufferId>,
22452    },
22453    BufferFoldToggled {
22454        ids: Vec<ExcerptId>,
22455        folded: bool,
22456    },
22457    ExcerptsEdited {
22458        ids: Vec<ExcerptId>,
22459    },
22460    ExcerptsExpanded {
22461        ids: Vec<ExcerptId>,
22462    },
22463    BufferEdited,
22464    Edited {
22465        transaction_id: clock::Lamport,
22466    },
22467    Reparsed(BufferId),
22468    Focused,
22469    FocusedIn,
22470    Blurred,
22471    DirtyChanged,
22472    Saved,
22473    TitleChanged,
22474    DiffBaseChanged,
22475    SelectionsChanged {
22476        local: bool,
22477    },
22478    ScrollPositionChanged {
22479        local: bool,
22480        autoscroll: bool,
22481    },
22482    Closed,
22483    TransactionUndone {
22484        transaction_id: clock::Lamport,
22485    },
22486    TransactionBegun {
22487        transaction_id: clock::Lamport,
22488    },
22489    Reloaded,
22490    CursorShapeChanged,
22491    PushedToNavHistory {
22492        anchor: Anchor,
22493        is_deactivate: bool,
22494    },
22495}
22496
22497impl EventEmitter<EditorEvent> for Editor {}
22498
22499impl Focusable for Editor {
22500    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22501        self.focus_handle.clone()
22502    }
22503}
22504
22505impl Render for Editor {
22506    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22507        let settings = ThemeSettings::get_global(cx);
22508
22509        let mut text_style = match self.mode {
22510            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22511                color: cx.theme().colors().editor_foreground,
22512                font_family: settings.ui_font.family.clone(),
22513                font_features: settings.ui_font.features.clone(),
22514                font_fallbacks: settings.ui_font.fallbacks.clone(),
22515                font_size: rems(0.875).into(),
22516                font_weight: settings.ui_font.weight,
22517                line_height: relative(settings.buffer_line_height.value()),
22518                ..Default::default()
22519            },
22520            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22521                color: cx.theme().colors().editor_foreground,
22522                font_family: settings.buffer_font.family.clone(),
22523                font_features: settings.buffer_font.features.clone(),
22524                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22525                font_size: settings.buffer_font_size(cx).into(),
22526                font_weight: settings.buffer_font.weight,
22527                line_height: relative(settings.buffer_line_height.value()),
22528                ..Default::default()
22529            },
22530        };
22531        if let Some(text_style_refinement) = &self.text_style_refinement {
22532            text_style.refine(text_style_refinement)
22533        }
22534
22535        let background = match self.mode {
22536            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22537            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22538            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22539            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22540        };
22541
22542        EditorElement::new(
22543            &cx.entity(),
22544            EditorStyle {
22545                background,
22546                border: cx.theme().colors().border,
22547                local_player: cx.theme().players().local(),
22548                text: text_style,
22549                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22550                syntax: cx.theme().syntax().clone(),
22551                status: cx.theme().status().clone(),
22552                inlay_hints_style: make_inlay_hints_style(cx),
22553                inline_completion_styles: make_suggestion_styles(cx),
22554                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22555                show_underlines: self.diagnostics_enabled(),
22556            },
22557        )
22558    }
22559}
22560
22561impl EntityInputHandler for Editor {
22562    fn text_for_range(
22563        &mut self,
22564        range_utf16: Range<usize>,
22565        adjusted_range: &mut Option<Range<usize>>,
22566        _: &mut Window,
22567        cx: &mut Context<Self>,
22568    ) -> Option<String> {
22569        let snapshot = self.buffer.read(cx).read(cx);
22570        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22571        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22572        if (start.0..end.0) != range_utf16 {
22573            adjusted_range.replace(start.0..end.0);
22574        }
22575        Some(snapshot.text_for_range(start..end).collect())
22576    }
22577
22578    fn selected_text_range(
22579        &mut self,
22580        ignore_disabled_input: bool,
22581        _: &mut Window,
22582        cx: &mut Context<Self>,
22583    ) -> Option<UTF16Selection> {
22584        // Prevent the IME menu from appearing when holding down an alphabetic key
22585        // while input is disabled.
22586        if !ignore_disabled_input && !self.input_enabled {
22587            return None;
22588        }
22589
22590        let selection = self.selections.newest::<OffsetUtf16>(cx);
22591        let range = selection.range();
22592
22593        Some(UTF16Selection {
22594            range: range.start.0..range.end.0,
22595            reversed: selection.reversed,
22596        })
22597    }
22598
22599    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22600        let snapshot = self.buffer.read(cx).read(cx);
22601        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22602        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22603    }
22604
22605    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22606        self.clear_highlights::<InputComposition>(cx);
22607        self.ime_transaction.take();
22608    }
22609
22610    fn replace_text_in_range(
22611        &mut self,
22612        range_utf16: Option<Range<usize>>,
22613        text: &str,
22614        window: &mut Window,
22615        cx: &mut Context<Self>,
22616    ) {
22617        if !self.input_enabled {
22618            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22619            return;
22620        }
22621
22622        self.transact(window, cx, |this, window, cx| {
22623            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22624                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22625                Some(this.selection_replacement_ranges(range_utf16, cx))
22626            } else {
22627                this.marked_text_ranges(cx)
22628            };
22629
22630            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22631                let newest_selection_id = this.selections.newest_anchor().id;
22632                this.selections
22633                    .all::<OffsetUtf16>(cx)
22634                    .iter()
22635                    .zip(ranges_to_replace.iter())
22636                    .find_map(|(selection, range)| {
22637                        if selection.id == newest_selection_id {
22638                            Some(
22639                                (range.start.0 as isize - selection.head().0 as isize)
22640                                    ..(range.end.0 as isize - selection.head().0 as isize),
22641                            )
22642                        } else {
22643                            None
22644                        }
22645                    })
22646            });
22647
22648            cx.emit(EditorEvent::InputHandled {
22649                utf16_range_to_replace: range_to_replace,
22650                text: text.into(),
22651            });
22652
22653            if let Some(new_selected_ranges) = new_selected_ranges {
22654                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22655                    selections.select_ranges(new_selected_ranges)
22656                });
22657                this.backspace(&Default::default(), window, cx);
22658            }
22659
22660            this.handle_input(text, window, cx);
22661        });
22662
22663        if let Some(transaction) = self.ime_transaction {
22664            self.buffer.update(cx, |buffer, cx| {
22665                buffer.group_until_transaction(transaction, cx);
22666            });
22667        }
22668
22669        self.unmark_text(window, cx);
22670    }
22671
22672    fn replace_and_mark_text_in_range(
22673        &mut self,
22674        range_utf16: Option<Range<usize>>,
22675        text: &str,
22676        new_selected_range_utf16: Option<Range<usize>>,
22677        window: &mut Window,
22678        cx: &mut Context<Self>,
22679    ) {
22680        if !self.input_enabled {
22681            return;
22682        }
22683
22684        let transaction = self.transact(window, cx, |this, window, cx| {
22685            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22686                let snapshot = this.buffer.read(cx).read(cx);
22687                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22688                    for marked_range in &mut marked_ranges {
22689                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22690                        marked_range.start.0 += relative_range_utf16.start;
22691                        marked_range.start =
22692                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22693                        marked_range.end =
22694                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22695                    }
22696                }
22697                Some(marked_ranges)
22698            } else if let Some(range_utf16) = range_utf16 {
22699                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22700                Some(this.selection_replacement_ranges(range_utf16, cx))
22701            } else {
22702                None
22703            };
22704
22705            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22706                let newest_selection_id = this.selections.newest_anchor().id;
22707                this.selections
22708                    .all::<OffsetUtf16>(cx)
22709                    .iter()
22710                    .zip(ranges_to_replace.iter())
22711                    .find_map(|(selection, range)| {
22712                        if selection.id == newest_selection_id {
22713                            Some(
22714                                (range.start.0 as isize - selection.head().0 as isize)
22715                                    ..(range.end.0 as isize - selection.head().0 as isize),
22716                            )
22717                        } else {
22718                            None
22719                        }
22720                    })
22721            });
22722
22723            cx.emit(EditorEvent::InputHandled {
22724                utf16_range_to_replace: range_to_replace,
22725                text: text.into(),
22726            });
22727
22728            if let Some(ranges) = ranges_to_replace {
22729                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22730                    s.select_ranges(ranges)
22731                });
22732            }
22733
22734            let marked_ranges = {
22735                let snapshot = this.buffer.read(cx).read(cx);
22736                this.selections
22737                    .disjoint_anchors()
22738                    .iter()
22739                    .map(|selection| {
22740                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22741                    })
22742                    .collect::<Vec<_>>()
22743            };
22744
22745            if text.is_empty() {
22746                this.unmark_text(window, cx);
22747            } else {
22748                this.highlight_text::<InputComposition>(
22749                    marked_ranges.clone(),
22750                    HighlightStyle {
22751                        underline: Some(UnderlineStyle {
22752                            thickness: px(1.),
22753                            color: None,
22754                            wavy: false,
22755                        }),
22756                        ..Default::default()
22757                    },
22758                    cx,
22759                );
22760            }
22761
22762            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22763            let use_autoclose = this.use_autoclose;
22764            let use_auto_surround = this.use_auto_surround;
22765            this.set_use_autoclose(false);
22766            this.set_use_auto_surround(false);
22767            this.handle_input(text, window, cx);
22768            this.set_use_autoclose(use_autoclose);
22769            this.set_use_auto_surround(use_auto_surround);
22770
22771            if let Some(new_selected_range) = new_selected_range_utf16 {
22772                let snapshot = this.buffer.read(cx).read(cx);
22773                let new_selected_ranges = marked_ranges
22774                    .into_iter()
22775                    .map(|marked_range| {
22776                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22777                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22778                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22779                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22780                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22781                    })
22782                    .collect::<Vec<_>>();
22783
22784                drop(snapshot);
22785                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22786                    selections.select_ranges(new_selected_ranges)
22787                });
22788            }
22789        });
22790
22791        self.ime_transaction = self.ime_transaction.or(transaction);
22792        if let Some(transaction) = self.ime_transaction {
22793            self.buffer.update(cx, |buffer, cx| {
22794                buffer.group_until_transaction(transaction, cx);
22795            });
22796        }
22797
22798        if self.text_highlights::<InputComposition>(cx).is_none() {
22799            self.ime_transaction.take();
22800        }
22801    }
22802
22803    fn bounds_for_range(
22804        &mut self,
22805        range_utf16: Range<usize>,
22806        element_bounds: gpui::Bounds<Pixels>,
22807        window: &mut Window,
22808        cx: &mut Context<Self>,
22809    ) -> Option<gpui::Bounds<Pixels>> {
22810        let text_layout_details = self.text_layout_details(window);
22811        let CharacterDimensions {
22812            em_width,
22813            em_advance,
22814            line_height,
22815        } = self.character_dimensions(window);
22816
22817        let snapshot = self.snapshot(window, cx);
22818        let scroll_position = snapshot.scroll_position();
22819        let scroll_left = scroll_position.x * em_advance;
22820
22821        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22822        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22823            + self.gutter_dimensions.full_width();
22824        let y = line_height * (start.row().as_f32() - scroll_position.y);
22825
22826        Some(Bounds {
22827            origin: element_bounds.origin + point(x, y),
22828            size: size(em_width, line_height),
22829        })
22830    }
22831
22832    fn character_index_for_point(
22833        &mut self,
22834        point: gpui::Point<Pixels>,
22835        _window: &mut Window,
22836        _cx: &mut Context<Self>,
22837    ) -> Option<usize> {
22838        let position_map = self.last_position_map.as_ref()?;
22839        if !position_map.text_hitbox.contains(&point) {
22840            return None;
22841        }
22842        let display_point = position_map.point_for_position(point).previous_valid;
22843        let anchor = position_map
22844            .snapshot
22845            .display_point_to_anchor(display_point, Bias::Left);
22846        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22847        Some(utf16_offset.0)
22848    }
22849}
22850
22851trait SelectionExt {
22852    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22853    fn spanned_rows(
22854        &self,
22855        include_end_if_at_line_start: bool,
22856        map: &DisplaySnapshot,
22857    ) -> Range<MultiBufferRow>;
22858}
22859
22860impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22861    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22862        let start = self
22863            .start
22864            .to_point(&map.buffer_snapshot)
22865            .to_display_point(map);
22866        let end = self
22867            .end
22868            .to_point(&map.buffer_snapshot)
22869            .to_display_point(map);
22870        if self.reversed {
22871            end..start
22872        } else {
22873            start..end
22874        }
22875    }
22876
22877    fn spanned_rows(
22878        &self,
22879        include_end_if_at_line_start: bool,
22880        map: &DisplaySnapshot,
22881    ) -> Range<MultiBufferRow> {
22882        let start = self.start.to_point(&map.buffer_snapshot);
22883        let mut end = self.end.to_point(&map.buffer_snapshot);
22884        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22885            end.row -= 1;
22886        }
22887
22888        let buffer_start = map.prev_line_boundary(start).0;
22889        let buffer_end = map.next_line_boundary(end).0;
22890        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22891    }
22892}
22893
22894impl<T: InvalidationRegion> InvalidationStack<T> {
22895    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22896    where
22897        S: Clone + ToOffset,
22898    {
22899        while let Some(region) = self.last() {
22900            let all_selections_inside_invalidation_ranges =
22901                if selections.len() == region.ranges().len() {
22902                    selections
22903                        .iter()
22904                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22905                        .all(|(selection, invalidation_range)| {
22906                            let head = selection.head().to_offset(buffer);
22907                            invalidation_range.start <= head && invalidation_range.end >= head
22908                        })
22909                } else {
22910                    false
22911                };
22912
22913            if all_selections_inside_invalidation_ranges {
22914                break;
22915            } else {
22916                self.pop();
22917            }
22918        }
22919    }
22920}
22921
22922impl<T> Default for InvalidationStack<T> {
22923    fn default() -> Self {
22924        Self(Default::default())
22925    }
22926}
22927
22928impl<T> Deref for InvalidationStack<T> {
22929    type Target = Vec<T>;
22930
22931    fn deref(&self) -> &Self::Target {
22932        &self.0
22933    }
22934}
22935
22936impl<T> DerefMut for InvalidationStack<T> {
22937    fn deref_mut(&mut self) -> &mut Self::Target {
22938        &mut self.0
22939    }
22940}
22941
22942impl InvalidationRegion for SnippetState {
22943    fn ranges(&self) -> &[Range<Anchor>] {
22944        &self.ranges[self.active_index]
22945    }
22946}
22947
22948fn inline_completion_edit_text(
22949    current_snapshot: &BufferSnapshot,
22950    edits: &[(Range<Anchor>, String)],
22951    edit_preview: &EditPreview,
22952    include_deletions: bool,
22953    cx: &App,
22954) -> HighlightedText {
22955    let edits = edits
22956        .iter()
22957        .map(|(anchor, text)| {
22958            (
22959                anchor.start.text_anchor..anchor.end.text_anchor,
22960                text.clone(),
22961            )
22962        })
22963        .collect::<Vec<_>>();
22964
22965    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22966}
22967
22968pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22969    match severity {
22970        lsp::DiagnosticSeverity::ERROR => colors.error,
22971        lsp::DiagnosticSeverity::WARNING => colors.warning,
22972        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22973        lsp::DiagnosticSeverity::HINT => colors.info,
22974        _ => colors.ignored,
22975    }
22976}
22977
22978pub fn styled_runs_for_code_label<'a>(
22979    label: &'a CodeLabel,
22980    syntax_theme: &'a theme::SyntaxTheme,
22981) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22982    let fade_out = HighlightStyle {
22983        fade_out: Some(0.35),
22984        ..Default::default()
22985    };
22986
22987    let mut prev_end = label.filter_range.end;
22988    label
22989        .runs
22990        .iter()
22991        .enumerate()
22992        .flat_map(move |(ix, (range, highlight_id))| {
22993            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22994                style
22995            } else {
22996                return Default::default();
22997            };
22998            let mut muted_style = style;
22999            muted_style.highlight(fade_out);
23000
23001            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23002            if range.start >= label.filter_range.end {
23003                if range.start > prev_end {
23004                    runs.push((prev_end..range.start, fade_out));
23005                }
23006                runs.push((range.clone(), muted_style));
23007            } else if range.end <= label.filter_range.end {
23008                runs.push((range.clone(), style));
23009            } else {
23010                runs.push((range.start..label.filter_range.end, style));
23011                runs.push((label.filter_range.end..range.end, muted_style));
23012            }
23013            prev_end = cmp::max(prev_end, range.end);
23014
23015            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23016                runs.push((prev_end..label.text.len(), fade_out));
23017            }
23018
23019            runs
23020        })
23021}
23022
23023pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23024    let mut prev_index = 0;
23025    let mut prev_codepoint: Option<char> = None;
23026    text.char_indices()
23027        .chain([(text.len(), '\0')])
23028        .filter_map(move |(index, codepoint)| {
23029            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23030            let is_boundary = index == text.len()
23031                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23032                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23033            if is_boundary {
23034                let chunk = &text[prev_index..index];
23035                prev_index = index;
23036                Some(chunk)
23037            } else {
23038                None
23039            }
23040        })
23041}
23042
23043pub trait RangeToAnchorExt: Sized {
23044    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23045
23046    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23047        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23048        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23049    }
23050}
23051
23052impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23053    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23054        let start_offset = self.start.to_offset(snapshot);
23055        let end_offset = self.end.to_offset(snapshot);
23056        if start_offset == end_offset {
23057            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23058        } else {
23059            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23060        }
23061    }
23062}
23063
23064pub trait RowExt {
23065    fn as_f32(&self) -> f32;
23066
23067    fn next_row(&self) -> Self;
23068
23069    fn previous_row(&self) -> Self;
23070
23071    fn minus(&self, other: Self) -> u32;
23072}
23073
23074impl RowExt for DisplayRow {
23075    fn as_f32(&self) -> f32 {
23076        self.0 as f32
23077    }
23078
23079    fn next_row(&self) -> Self {
23080        Self(self.0 + 1)
23081    }
23082
23083    fn previous_row(&self) -> Self {
23084        Self(self.0.saturating_sub(1))
23085    }
23086
23087    fn minus(&self, other: Self) -> u32 {
23088        self.0 - other.0
23089    }
23090}
23091
23092impl RowExt for MultiBufferRow {
23093    fn as_f32(&self) -> f32 {
23094        self.0 as f32
23095    }
23096
23097    fn next_row(&self) -> Self {
23098        Self(self.0 + 1)
23099    }
23100
23101    fn previous_row(&self) -> Self {
23102        Self(self.0.saturating_sub(1))
23103    }
23104
23105    fn minus(&self, other: Self) -> u32 {
23106        self.0 - other.0
23107    }
23108}
23109
23110trait RowRangeExt {
23111    type Row;
23112
23113    fn len(&self) -> usize;
23114
23115    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23116}
23117
23118impl RowRangeExt for Range<MultiBufferRow> {
23119    type Row = MultiBufferRow;
23120
23121    fn len(&self) -> usize {
23122        (self.end.0 - self.start.0) as usize
23123    }
23124
23125    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23126        (self.start.0..self.end.0).map(MultiBufferRow)
23127    }
23128}
23129
23130impl RowRangeExt for Range<DisplayRow> {
23131    type Row = DisplayRow;
23132
23133    fn len(&self) -> usize {
23134        (self.end.0 - self.start.0) as usize
23135    }
23136
23137    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23138        (self.start.0..self.end.0).map(DisplayRow)
23139    }
23140}
23141
23142/// If select range has more than one line, we
23143/// just point the cursor to range.start.
23144fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23145    if range.start.row == range.end.row {
23146        range
23147    } else {
23148        range.start..range.start
23149    }
23150}
23151pub struct KillRing(ClipboardItem);
23152impl Global for KillRing {}
23153
23154const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23155
23156enum BreakpointPromptEditAction {
23157    Log,
23158    Condition,
23159    HitCondition,
23160}
23161
23162struct BreakpointPromptEditor {
23163    pub(crate) prompt: Entity<Editor>,
23164    editor: WeakEntity<Editor>,
23165    breakpoint_anchor: Anchor,
23166    breakpoint: Breakpoint,
23167    edit_action: BreakpointPromptEditAction,
23168    block_ids: HashSet<CustomBlockId>,
23169    editor_margins: Arc<Mutex<EditorMargins>>,
23170    _subscriptions: Vec<Subscription>,
23171}
23172
23173impl BreakpointPromptEditor {
23174    const MAX_LINES: u8 = 4;
23175
23176    fn new(
23177        editor: WeakEntity<Editor>,
23178        breakpoint_anchor: Anchor,
23179        breakpoint: Breakpoint,
23180        edit_action: BreakpointPromptEditAction,
23181        window: &mut Window,
23182        cx: &mut Context<Self>,
23183    ) -> Self {
23184        let base_text = match edit_action {
23185            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23186            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23187            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23188        }
23189        .map(|msg| msg.to_string())
23190        .unwrap_or_default();
23191
23192        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23193        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23194
23195        let prompt = cx.new(|cx| {
23196            let mut prompt = Editor::new(
23197                EditorMode::AutoHeight {
23198                    min_lines: 1,
23199                    max_lines: Some(Self::MAX_LINES as usize),
23200                },
23201                buffer,
23202                None,
23203                window,
23204                cx,
23205            );
23206            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23207            prompt.set_show_cursor_when_unfocused(false, cx);
23208            prompt.set_placeholder_text(
23209                match edit_action {
23210                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23211                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23212                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23213                },
23214                cx,
23215            );
23216
23217            prompt
23218        });
23219
23220        Self {
23221            prompt,
23222            editor,
23223            breakpoint_anchor,
23224            breakpoint,
23225            edit_action,
23226            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23227            block_ids: Default::default(),
23228            _subscriptions: vec![],
23229        }
23230    }
23231
23232    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23233        self.block_ids.extend(block_ids)
23234    }
23235
23236    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23237        if let Some(editor) = self.editor.upgrade() {
23238            let message = self
23239                .prompt
23240                .read(cx)
23241                .buffer
23242                .read(cx)
23243                .as_singleton()
23244                .expect("A multi buffer in breakpoint prompt isn't possible")
23245                .read(cx)
23246                .as_rope()
23247                .to_string();
23248
23249            editor.update(cx, |editor, cx| {
23250                editor.edit_breakpoint_at_anchor(
23251                    self.breakpoint_anchor,
23252                    self.breakpoint.clone(),
23253                    match self.edit_action {
23254                        BreakpointPromptEditAction::Log => {
23255                            BreakpointEditAction::EditLogMessage(message.into())
23256                        }
23257                        BreakpointPromptEditAction::Condition => {
23258                            BreakpointEditAction::EditCondition(message.into())
23259                        }
23260                        BreakpointPromptEditAction::HitCondition => {
23261                            BreakpointEditAction::EditHitCondition(message.into())
23262                        }
23263                    },
23264                    cx,
23265                );
23266
23267                editor.remove_blocks(self.block_ids.clone(), None, cx);
23268                cx.focus_self(window);
23269            });
23270        }
23271    }
23272
23273    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23274        self.editor
23275            .update(cx, |editor, cx| {
23276                editor.remove_blocks(self.block_ids.clone(), None, cx);
23277                window.focus(&editor.focus_handle);
23278            })
23279            .log_err();
23280    }
23281
23282    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23283        let settings = ThemeSettings::get_global(cx);
23284        let text_style = TextStyle {
23285            color: if self.prompt.read(cx).read_only(cx) {
23286                cx.theme().colors().text_disabled
23287            } else {
23288                cx.theme().colors().text
23289            },
23290            font_family: settings.buffer_font.family.clone(),
23291            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23292            font_size: settings.buffer_font_size(cx).into(),
23293            font_weight: settings.buffer_font.weight,
23294            line_height: relative(settings.buffer_line_height.value()),
23295            ..Default::default()
23296        };
23297        EditorElement::new(
23298            &self.prompt,
23299            EditorStyle {
23300                background: cx.theme().colors().editor_background,
23301                local_player: cx.theme().players().local(),
23302                text: text_style,
23303                ..Default::default()
23304            },
23305        )
23306    }
23307}
23308
23309impl Render for BreakpointPromptEditor {
23310    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23311        let editor_margins = *self.editor_margins.lock();
23312        let gutter_dimensions = editor_margins.gutter;
23313        h_flex()
23314            .key_context("Editor")
23315            .bg(cx.theme().colors().editor_background)
23316            .border_y_1()
23317            .border_color(cx.theme().status().info_border)
23318            .size_full()
23319            .py(window.line_height() / 2.5)
23320            .on_action(cx.listener(Self::confirm))
23321            .on_action(cx.listener(Self::cancel))
23322            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23323            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23324    }
23325}
23326
23327impl Focusable for BreakpointPromptEditor {
23328    fn focus_handle(&self, cx: &App) -> FocusHandle {
23329        self.prompt.focus_handle(cx)
23330    }
23331}
23332
23333fn all_edits_insertions_or_deletions(
23334    edits: &Vec<(Range<Anchor>, String)>,
23335    snapshot: &MultiBufferSnapshot,
23336) -> bool {
23337    let mut all_insertions = true;
23338    let mut all_deletions = true;
23339
23340    for (range, new_text) in edits.iter() {
23341        let range_is_empty = range.to_offset(&snapshot).is_empty();
23342        let text_is_empty = new_text.is_empty();
23343
23344        if range_is_empty != text_is_empty {
23345            if range_is_empty {
23346                all_deletions = false;
23347            } else {
23348                all_insertions = false;
23349            }
23350        } else {
23351            return false;
23352        }
23353
23354        if !all_insertions && !all_deletions {
23355            return false;
23356        }
23357    }
23358    all_insertions || all_deletions
23359}
23360
23361struct MissingEditPredictionKeybindingTooltip;
23362
23363impl Render for MissingEditPredictionKeybindingTooltip {
23364    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23365        ui::tooltip_container(window, cx, |container, _, cx| {
23366            container
23367                .flex_shrink_0()
23368                .max_w_80()
23369                .min_h(rems_from_px(124.))
23370                .justify_between()
23371                .child(
23372                    v_flex()
23373                        .flex_1()
23374                        .text_ui_sm(cx)
23375                        .child(Label::new("Conflict with Accept Keybinding"))
23376                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23377                )
23378                .child(
23379                    h_flex()
23380                        .pb_1()
23381                        .gap_1()
23382                        .items_end()
23383                        .w_full()
23384                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23385                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23386                        }))
23387                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23388                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23389                        })),
23390                )
23391        })
23392    }
23393}
23394
23395#[derive(Debug, Clone, Copy, PartialEq)]
23396pub struct LineHighlight {
23397    pub background: Background,
23398    pub border: Option<gpui::Hsla>,
23399    pub include_gutter: bool,
23400    pub type_id: Option<TypeId>,
23401}
23402
23403struct LineManipulationResult {
23404    pub new_text: String,
23405    pub line_count_before: usize,
23406    pub line_count_after: usize,
23407}
23408
23409fn render_diff_hunk_controls(
23410    row: u32,
23411    status: &DiffHunkStatus,
23412    hunk_range: Range<Anchor>,
23413    is_created_file: bool,
23414    line_height: Pixels,
23415    editor: &Entity<Editor>,
23416    _window: &mut Window,
23417    cx: &mut App,
23418) -> AnyElement {
23419    h_flex()
23420        .h(line_height)
23421        .mr_1()
23422        .gap_1()
23423        .px_0p5()
23424        .pb_1()
23425        .border_x_1()
23426        .border_b_1()
23427        .border_color(cx.theme().colors().border_variant)
23428        .rounded_b_lg()
23429        .bg(cx.theme().colors().editor_background)
23430        .gap_1()
23431        .block_mouse_except_scroll()
23432        .shadow_md()
23433        .child(if status.has_secondary_hunk() {
23434            Button::new(("stage", row as u64), "Stage")
23435                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23436                .tooltip({
23437                    let focus_handle = editor.focus_handle(cx);
23438                    move |window, cx| {
23439                        Tooltip::for_action_in(
23440                            "Stage Hunk",
23441                            &::git::ToggleStaged,
23442                            &focus_handle,
23443                            window,
23444                            cx,
23445                        )
23446                    }
23447                })
23448                .on_click({
23449                    let editor = editor.clone();
23450                    move |_event, _window, cx| {
23451                        editor.update(cx, |editor, cx| {
23452                            editor.stage_or_unstage_diff_hunks(
23453                                true,
23454                                vec![hunk_range.start..hunk_range.start],
23455                                cx,
23456                            );
23457                        });
23458                    }
23459                })
23460        } else {
23461            Button::new(("unstage", row as u64), "Unstage")
23462                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23463                .tooltip({
23464                    let focus_handle = editor.focus_handle(cx);
23465                    move |window, cx| {
23466                        Tooltip::for_action_in(
23467                            "Unstage Hunk",
23468                            &::git::ToggleStaged,
23469                            &focus_handle,
23470                            window,
23471                            cx,
23472                        )
23473                    }
23474                })
23475                .on_click({
23476                    let editor = editor.clone();
23477                    move |_event, _window, cx| {
23478                        editor.update(cx, |editor, cx| {
23479                            editor.stage_or_unstage_diff_hunks(
23480                                false,
23481                                vec![hunk_range.start..hunk_range.start],
23482                                cx,
23483                            );
23484                        });
23485                    }
23486                })
23487        })
23488        .child(
23489            Button::new(("restore", row as u64), "Restore")
23490                .tooltip({
23491                    let focus_handle = editor.focus_handle(cx);
23492                    move |window, cx| {
23493                        Tooltip::for_action_in(
23494                            "Restore Hunk",
23495                            &::git::Restore,
23496                            &focus_handle,
23497                            window,
23498                            cx,
23499                        )
23500                    }
23501                })
23502                .on_click({
23503                    let editor = editor.clone();
23504                    move |_event, window, cx| {
23505                        editor.update(cx, |editor, cx| {
23506                            let snapshot = editor.snapshot(window, cx);
23507                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23508                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23509                        });
23510                    }
23511                })
23512                .disabled(is_created_file),
23513        )
23514        .when(
23515            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23516            |el| {
23517                el.child(
23518                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23519                        .shape(IconButtonShape::Square)
23520                        .icon_size(IconSize::Small)
23521                        // .disabled(!has_multiple_hunks)
23522                        .tooltip({
23523                            let focus_handle = editor.focus_handle(cx);
23524                            move |window, cx| {
23525                                Tooltip::for_action_in(
23526                                    "Next Hunk",
23527                                    &GoToHunk,
23528                                    &focus_handle,
23529                                    window,
23530                                    cx,
23531                                )
23532                            }
23533                        })
23534                        .on_click({
23535                            let editor = editor.clone();
23536                            move |_event, window, cx| {
23537                                editor.update(cx, |editor, cx| {
23538                                    let snapshot = editor.snapshot(window, cx);
23539                                    let position =
23540                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23541                                    editor.go_to_hunk_before_or_after_position(
23542                                        &snapshot,
23543                                        position,
23544                                        Direction::Next,
23545                                        window,
23546                                        cx,
23547                                    );
23548                                    editor.expand_selected_diff_hunks(cx);
23549                                });
23550                            }
23551                        }),
23552                )
23553                .child(
23554                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23555                        .shape(IconButtonShape::Square)
23556                        .icon_size(IconSize::Small)
23557                        // .disabled(!has_multiple_hunks)
23558                        .tooltip({
23559                            let focus_handle = editor.focus_handle(cx);
23560                            move |window, cx| {
23561                                Tooltip::for_action_in(
23562                                    "Previous Hunk",
23563                                    &GoToPreviousHunk,
23564                                    &focus_handle,
23565                                    window,
23566                                    cx,
23567                                )
23568                            }
23569                        })
23570                        .on_click({
23571                            let editor = editor.clone();
23572                            move |_event, window, cx| {
23573                                editor.update(cx, |editor, cx| {
23574                                    let snapshot = editor.snapshot(window, cx);
23575                                    let point =
23576                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23577                                    editor.go_to_hunk_before_or_after_position(
23578                                        &snapshot,
23579                                        point,
23580                                        Direction::Prev,
23581                                        window,
23582                                        cx,
23583                                    );
23584                                    editor.expand_selected_diff_hunks(cx);
23585                                });
23586                            }
23587                        }),
23588                )
23589            },
23590        )
23591        .into_any_element()
23592}