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        auto_width: bool,
  487    },
  488    AutoHeight {
  489        min_lines: usize,
  490        max_lines: Option<usize>,
  491    },
  492    Full {
  493        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  494        scale_ui_elements_with_buffer_font_size: bool,
  495        /// When set to `true`, the editor will render a background for the active line.
  496        show_active_line_background: bool,
  497        /// When set to `true`, the editor's height will be determined by its content.
  498        sized_by_content: bool,
  499    },
  500    Minimap {
  501        parent: WeakEntity<Editor>,
  502    },
  503}
  504
  505impl EditorMode {
  506    pub fn full() -> Self {
  507        Self::Full {
  508            scale_ui_elements_with_buffer_font_size: true,
  509            show_active_line_background: true,
  510            sized_by_content: false,
  511        }
  512    }
  513
  514    #[inline]
  515    pub fn is_full(&self) -> bool {
  516        matches!(self, Self::Full { .. })
  517    }
  518
  519    #[inline]
  520    pub fn is_single_line(&self) -> bool {
  521        matches!(self, Self::SingleLine { .. })
  522    }
  523
  524    #[inline]
  525    fn is_minimap(&self) -> bool {
  526        matches!(self, Self::Minimap { .. })
  527    }
  528}
  529
  530#[derive(Copy, Clone, Debug)]
  531pub enum SoftWrap {
  532    /// Prefer not to wrap at all.
  533    ///
  534    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  535    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  536    GitDiff,
  537    /// Prefer a single line generally, unless an overly long line is encountered.
  538    None,
  539    /// Soft wrap lines that exceed the editor width.
  540    EditorWidth,
  541    /// Soft wrap lines at the preferred line length.
  542    Column(u32),
  543    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  544    Bounded(u32),
  545}
  546
  547#[derive(Clone)]
  548pub struct EditorStyle {
  549    pub background: Hsla,
  550    pub border: Hsla,
  551    pub local_player: PlayerColor,
  552    pub text: TextStyle,
  553    pub scrollbar_width: Pixels,
  554    pub syntax: Arc<SyntaxTheme>,
  555    pub status: StatusColors,
  556    pub inlay_hints_style: HighlightStyle,
  557    pub inline_completion_styles: InlineCompletionStyles,
  558    pub unnecessary_code_fade: f32,
  559    pub show_underlines: bool,
  560}
  561
  562impl Default for EditorStyle {
  563    fn default() -> Self {
  564        Self {
  565            background: Hsla::default(),
  566            border: Hsla::default(),
  567            local_player: PlayerColor::default(),
  568            text: TextStyle::default(),
  569            scrollbar_width: Pixels::default(),
  570            syntax: Default::default(),
  571            // HACK: Status colors don't have a real default.
  572            // We should look into removing the status colors from the editor
  573            // style and retrieve them directly from the theme.
  574            status: StatusColors::dark(),
  575            inlay_hints_style: HighlightStyle::default(),
  576            inline_completion_styles: InlineCompletionStyles {
  577                insertion: HighlightStyle::default(),
  578                whitespace: HighlightStyle::default(),
  579            },
  580            unnecessary_code_fade: Default::default(),
  581            show_underlines: true,
  582        }
  583    }
  584}
  585
  586pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  587    let show_background = language_settings::language_settings(None, None, cx)
  588        .inlay_hints
  589        .show_background;
  590
  591    HighlightStyle {
  592        color: Some(cx.theme().status().hint),
  593        background_color: show_background.then(|| cx.theme().status().hint_background),
  594        ..HighlightStyle::default()
  595    }
  596}
  597
  598pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  599    InlineCompletionStyles {
  600        insertion: HighlightStyle {
  601            color: Some(cx.theme().status().predictive),
  602            ..HighlightStyle::default()
  603        },
  604        whitespace: HighlightStyle {
  605            background_color: Some(cx.theme().status().created_background),
  606            ..HighlightStyle::default()
  607        },
  608    }
  609}
  610
  611type CompletionId = usize;
  612
  613pub(crate) enum EditDisplayMode {
  614    TabAccept,
  615    DiffPopover,
  616    Inline,
  617}
  618
  619enum InlineCompletion {
  620    Edit {
  621        edits: Vec<(Range<Anchor>, String)>,
  622        edit_preview: Option<EditPreview>,
  623        display_mode: EditDisplayMode,
  624        snapshot: BufferSnapshot,
  625    },
  626    Move {
  627        target: Anchor,
  628        snapshot: BufferSnapshot,
  629    },
  630}
  631
  632struct InlineCompletionState {
  633    inlay_ids: Vec<InlayId>,
  634    completion: InlineCompletion,
  635    completion_id: Option<SharedString>,
  636    invalidation_range: Range<Anchor>,
  637}
  638
  639enum EditPredictionSettings {
  640    Disabled,
  641    Enabled {
  642        show_in_menu: bool,
  643        preview_requires_modifier: bool,
  644    },
  645}
  646
  647enum InlineCompletionHighlight {}
  648
  649#[derive(Debug, Clone)]
  650struct InlineDiagnostic {
  651    message: SharedString,
  652    group_id: usize,
  653    is_primary: bool,
  654    start: Point,
  655    severity: lsp::DiagnosticSeverity,
  656}
  657
  658pub enum MenuInlineCompletionsPolicy {
  659    Never,
  660    ByProvider,
  661}
  662
  663pub enum EditPredictionPreview {
  664    /// Modifier is not pressed
  665    Inactive { released_too_fast: bool },
  666    /// Modifier pressed
  667    Active {
  668        since: Instant,
  669        previous_scroll_position: Option<ScrollAnchor>,
  670    },
  671}
  672
  673impl EditPredictionPreview {
  674    pub fn released_too_fast(&self) -> bool {
  675        match self {
  676            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  677            EditPredictionPreview::Active { .. } => false,
  678        }
  679    }
  680
  681    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  682        if let EditPredictionPreview::Active {
  683            previous_scroll_position,
  684            ..
  685        } = self
  686        {
  687            *previous_scroll_position = scroll_position;
  688        }
  689    }
  690}
  691
  692pub struct ContextMenuOptions {
  693    pub min_entries_visible: usize,
  694    pub max_entries_visible: usize,
  695    pub placement: Option<ContextMenuPlacement>,
  696}
  697
  698#[derive(Debug, Clone, PartialEq, Eq)]
  699pub enum ContextMenuPlacement {
  700    Above,
  701    Below,
  702}
  703
  704#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  705struct EditorActionId(usize);
  706
  707impl EditorActionId {
  708    pub fn post_inc(&mut self) -> Self {
  709        let answer = self.0;
  710
  711        *self = Self(answer + 1);
  712
  713        Self(answer)
  714    }
  715}
  716
  717// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  718// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  719
  720type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  721type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  722
  723#[derive(Default)]
  724struct ScrollbarMarkerState {
  725    scrollbar_size: Size<Pixels>,
  726    dirty: bool,
  727    markers: Arc<[PaintQuad]>,
  728    pending_refresh: Option<Task<Result<()>>>,
  729}
  730
  731impl ScrollbarMarkerState {
  732    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  733        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  734    }
  735}
  736
  737#[derive(Clone, Copy, PartialEq, Eq)]
  738pub enum MinimapVisibility {
  739    Disabled,
  740    Enabled {
  741        /// The configuration currently present in the users settings.
  742        setting_configuration: bool,
  743        /// Whether to override the currently set visibility from the users setting.
  744        toggle_override: bool,
  745    },
  746}
  747
  748impl MinimapVisibility {
  749    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  750        if mode.is_full() {
  751            Self::Enabled {
  752                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  753                toggle_override: false,
  754            }
  755        } else {
  756            Self::Disabled
  757        }
  758    }
  759
  760    fn hidden(&self) -> Self {
  761        match *self {
  762            Self::Enabled {
  763                setting_configuration,
  764                ..
  765            } => Self::Enabled {
  766                setting_configuration,
  767                toggle_override: setting_configuration,
  768            },
  769            Self::Disabled => Self::Disabled,
  770        }
  771    }
  772
  773    fn disabled(&self) -> bool {
  774        match *self {
  775            Self::Disabled => true,
  776            _ => false,
  777        }
  778    }
  779
  780    fn settings_visibility(&self) -> bool {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => setting_configuration,
  786            _ => false,
  787        }
  788    }
  789
  790    fn visible(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                toggle_override,
  795            } => setting_configuration ^ toggle_override,
  796            _ => false,
  797        }
  798    }
  799
  800    fn toggle_visibility(&self) -> Self {
  801        match *self {
  802            Self::Enabled {
  803                toggle_override,
  804                setting_configuration,
  805            } => Self::Enabled {
  806                setting_configuration,
  807                toggle_override: !toggle_override,
  808            },
  809            Self::Disabled => Self::Disabled,
  810        }
  811    }
  812}
  813
  814#[derive(Clone, Debug)]
  815struct RunnableTasks {
  816    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  817    offset: multi_buffer::Anchor,
  818    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  819    column: u32,
  820    // Values of all named captures, including those starting with '_'
  821    extra_variables: HashMap<String, String>,
  822    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  823    context_range: Range<BufferOffset>,
  824}
  825
  826impl RunnableTasks {
  827    fn resolve<'a>(
  828        &'a self,
  829        cx: &'a task::TaskContext,
  830    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  831        self.templates.iter().filter_map(|(kind, template)| {
  832            template
  833                .resolve_task(&kind.to_id_base(), cx)
  834                .map(|task| (kind.clone(), task))
  835        })
  836    }
  837}
  838
  839#[derive(Clone)]
  840pub struct ResolvedTasks {
  841    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  842    position: Anchor,
  843}
  844
  845#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  846struct BufferOffset(usize);
  847
  848// Addons allow storing per-editor state in other crates (e.g. Vim)
  849pub trait Addon: 'static {
  850    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  851
  852    fn render_buffer_header_controls(
  853        &self,
  854        _: &ExcerptInfo,
  855        _: &Window,
  856        _: &App,
  857    ) -> Option<AnyElement> {
  858        None
  859    }
  860
  861    fn to_any(&self) -> &dyn std::any::Any;
  862
  863    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  864        None
  865    }
  866}
  867
  868/// A set of caret positions, registered when the editor was edited.
  869pub struct ChangeList {
  870    changes: Vec<Vec<Anchor>>,
  871    /// Currently "selected" change.
  872    position: Option<usize>,
  873}
  874
  875impl ChangeList {
  876    pub fn new() -> Self {
  877        Self {
  878            changes: Vec::new(),
  879            position: None,
  880        }
  881    }
  882
  883    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  884    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  885    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  886        if self.changes.is_empty() {
  887            return None;
  888        }
  889
  890        let prev = self.position.unwrap_or(self.changes.len());
  891        let next = if direction == Direction::Prev {
  892            prev.saturating_sub(count)
  893        } else {
  894            (prev + count).min(self.changes.len() - 1)
  895        };
  896        self.position = Some(next);
  897        self.changes.get(next).map(|anchors| anchors.as_slice())
  898    }
  899
  900    /// Adds a new change to the list, resetting the change list position.
  901    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  902        self.position.take();
  903        if pop_state {
  904            self.changes.pop();
  905        }
  906        self.changes.push(new_positions.clone());
  907    }
  908
  909    pub fn last(&self) -> Option<&[Anchor]> {
  910        self.changes.last().map(|anchors| anchors.as_slice())
  911    }
  912}
  913
  914#[derive(Clone)]
  915struct InlineBlamePopoverState {
  916    scroll_handle: ScrollHandle,
  917    commit_message: Option<ParsedCommitMessage>,
  918    markdown: Entity<Markdown>,
  919}
  920
  921struct InlineBlamePopover {
  922    position: gpui::Point<Pixels>,
  923    hide_task: Option<Task<()>>,
  924    popover_bounds: Option<Bounds<Pixels>>,
  925    popover_state: InlineBlamePopoverState,
  926}
  927
  928enum SelectionDragState {
  929    /// State when no drag related activity is detected.
  930    None,
  931    /// State when the mouse is down on a selection that is about to be dragged.
  932    ReadyToDrag {
  933        selection: Selection<Anchor>,
  934        click_position: gpui::Point<Pixels>,
  935        mouse_down_time: Instant,
  936    },
  937    /// State when the mouse is dragging the selection in the editor.
  938    Dragging {
  939        selection: Selection<Anchor>,
  940        drop_cursor: Selection<Anchor>,
  941        hide_drop_cursor: bool,
  942    },
  943}
  944
  945enum ColumnarSelectionState {
  946    FromMouse {
  947        selection_tail: Anchor,
  948        display_point: Option<DisplayPoint>,
  949    },
  950    FromSelection {
  951        selection_tail: Anchor,
  952    },
  953}
  954
  955/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  956/// a breakpoint on them.
  957#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  958struct PhantomBreakpointIndicator {
  959    display_row: DisplayRow,
  960    /// There's a small debounce between hovering over the line and showing the indicator.
  961    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  962    is_active: bool,
  963    collides_with_existing_breakpoint: bool,
  964}
  965
  966/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  967///
  968/// See the [module level documentation](self) for more information.
  969pub struct Editor {
  970    focus_handle: FocusHandle,
  971    last_focused_descendant: Option<WeakFocusHandle>,
  972    /// The text buffer being edited
  973    buffer: Entity<MultiBuffer>,
  974    /// Map of how text in the buffer should be displayed.
  975    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  976    pub display_map: Entity<DisplayMap>,
  977    pub selections: SelectionsCollection,
  978    pub scroll_manager: ScrollManager,
  979    /// When inline assist editors are linked, they all render cursors because
  980    /// typing enters text into each of them, even the ones that aren't focused.
  981    pub(crate) show_cursor_when_unfocused: bool,
  982    columnar_selection_state: Option<ColumnarSelectionState>,
  983    add_selections_state: Option<AddSelectionsState>,
  984    select_next_state: Option<SelectNextState>,
  985    select_prev_state: Option<SelectNextState>,
  986    selection_history: SelectionHistory,
  987    defer_selection_effects: bool,
  988    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  989    autoclose_regions: Vec<AutocloseRegion>,
  990    snippet_stack: InvalidationStack<SnippetState>,
  991    select_syntax_node_history: SelectSyntaxNodeHistory,
  992    ime_transaction: Option<TransactionId>,
  993    pub diagnostics_max_severity: DiagnosticSeverity,
  994    active_diagnostics: ActiveDiagnostic,
  995    show_inline_diagnostics: bool,
  996    inline_diagnostics_update: Task<()>,
  997    inline_diagnostics_enabled: bool,
  998    diagnostics_enabled: bool,
  999    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1000    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1001    hard_wrap: Option<usize>,
 1002
 1003    // TODO: make this a access method
 1004    pub project: Option<Entity<Project>>,
 1005    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1006    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1007    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1008    blink_manager: Entity<BlinkManager>,
 1009    show_cursor_names: bool,
 1010    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1011    pub show_local_selections: bool,
 1012    mode: EditorMode,
 1013    show_breadcrumbs: bool,
 1014    show_gutter: bool,
 1015    show_scrollbars: ScrollbarAxes,
 1016    minimap_visibility: MinimapVisibility,
 1017    offset_content: bool,
 1018    disable_expand_excerpt_buttons: bool,
 1019    show_line_numbers: Option<bool>,
 1020    use_relative_line_numbers: Option<bool>,
 1021    show_git_diff_gutter: Option<bool>,
 1022    show_code_actions: Option<bool>,
 1023    show_runnables: Option<bool>,
 1024    show_breakpoints: Option<bool>,
 1025    show_wrap_guides: Option<bool>,
 1026    show_indent_guides: Option<bool>,
 1027    placeholder_text: Option<Arc<str>>,
 1028    highlight_order: usize,
 1029    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1030    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1031    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1032    scrollbar_marker_state: ScrollbarMarkerState,
 1033    active_indent_guides_state: ActiveIndentGuidesState,
 1034    nav_history: Option<ItemNavHistory>,
 1035    context_menu: RefCell<Option<CodeContextMenu>>,
 1036    context_menu_options: Option<ContextMenuOptions>,
 1037    mouse_context_menu: Option<MouseContextMenu>,
 1038    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1039    inline_blame_popover: Option<InlineBlamePopover>,
 1040    inline_blame_popover_show_task: Option<Task<()>>,
 1041    signature_help_state: SignatureHelpState,
 1042    auto_signature_help: Option<bool>,
 1043    find_all_references_task_sources: Vec<Anchor>,
 1044    next_completion_id: CompletionId,
 1045    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1046    code_actions_task: Option<Task<Result<()>>>,
 1047    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1048    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1049    document_highlights_task: Option<Task<()>>,
 1050    linked_editing_range_task: Option<Task<Option<()>>>,
 1051    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1052    pending_rename: Option<RenameState>,
 1053    searchable: bool,
 1054    cursor_shape: CursorShape,
 1055    current_line_highlight: Option<CurrentLineHighlight>,
 1056    collapse_matches: bool,
 1057    autoindent_mode: Option<AutoindentMode>,
 1058    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1059    input_enabled: bool,
 1060    use_modal_editing: bool,
 1061    read_only: bool,
 1062    leader_id: Option<CollaboratorId>,
 1063    remote_id: Option<ViewId>,
 1064    pub hover_state: HoverState,
 1065    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1066    gutter_hovered: bool,
 1067    hovered_link_state: Option<HoveredLinkState>,
 1068    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1069    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1070    active_inline_completion: Option<InlineCompletionState>,
 1071    /// Used to prevent flickering as the user types while the menu is open
 1072    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1073    edit_prediction_settings: EditPredictionSettings,
 1074    inline_completions_hidden_for_vim_mode: bool,
 1075    show_inline_completions_override: Option<bool>,
 1076    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1077    edit_prediction_preview: EditPredictionPreview,
 1078    edit_prediction_indent_conflict: bool,
 1079    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1080    inlay_hint_cache: InlayHintCache,
 1081    next_inlay_id: usize,
 1082    _subscriptions: Vec<Subscription>,
 1083    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1084    gutter_dimensions: GutterDimensions,
 1085    style: Option<EditorStyle>,
 1086    text_style_refinement: Option<TextStyleRefinement>,
 1087    next_editor_action_id: EditorActionId,
 1088    editor_actions: Rc<
 1089        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1090    >,
 1091    use_autoclose: bool,
 1092    use_auto_surround: bool,
 1093    auto_replace_emoji_shortcode: bool,
 1094    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1095    show_git_blame_gutter: bool,
 1096    show_git_blame_inline: bool,
 1097    show_git_blame_inline_delay_task: Option<Task<()>>,
 1098    git_blame_inline_enabled: bool,
 1099    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1100    serialize_dirty_buffers: bool,
 1101    show_selection_menu: Option<bool>,
 1102    blame: Option<Entity<GitBlame>>,
 1103    blame_subscription: Option<Subscription>,
 1104    custom_context_menu: Option<
 1105        Box<
 1106            dyn 'static
 1107                + Fn(
 1108                    &mut Self,
 1109                    DisplayPoint,
 1110                    &mut Window,
 1111                    &mut Context<Self>,
 1112                ) -> Option<Entity<ui::ContextMenu>>,
 1113        >,
 1114    >,
 1115    last_bounds: Option<Bounds<Pixels>>,
 1116    last_position_map: Option<Rc<PositionMap>>,
 1117    expect_bounds_change: Option<Bounds<Pixels>>,
 1118    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1119    tasks_update_task: Option<Task<()>>,
 1120    breakpoint_store: Option<Entity<BreakpointStore>>,
 1121    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1122    hovered_diff_hunk_row: Option<DisplayRow>,
 1123    pull_diagnostics_task: Task<()>,
 1124    in_project_search: bool,
 1125    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1126    breadcrumb_header: Option<String>,
 1127    focused_block: Option<FocusedBlock>,
 1128    next_scroll_position: NextScrollCursorCenterTopBottom,
 1129    addons: HashMap<TypeId, Box<dyn Addon>>,
 1130    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1131    load_diff_task: Option<Shared<Task<()>>>,
 1132    /// Whether we are temporarily displaying a diff other than git's
 1133    temporary_diff_override: bool,
 1134    selection_mark_mode: bool,
 1135    toggle_fold_multiple_buffers: Task<()>,
 1136    _scroll_cursor_center_top_bottom_task: Task<()>,
 1137    serialize_selections: Task<()>,
 1138    serialize_folds: Task<()>,
 1139    mouse_cursor_hidden: bool,
 1140    minimap: Option<Entity<Self>>,
 1141    hide_mouse_mode: HideMouseMode,
 1142    pub change_list: ChangeList,
 1143    inline_value_cache: InlineValueCache,
 1144    selection_drag_state: SelectionDragState,
 1145    drag_and_drop_selection_enabled: bool,
 1146    next_color_inlay_id: usize,
 1147    colors: Option<LspColorData>,
 1148    folding_newlines: Task<()>,
 1149}
 1150
 1151#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1152enum NextScrollCursorCenterTopBottom {
 1153    #[default]
 1154    Center,
 1155    Top,
 1156    Bottom,
 1157}
 1158
 1159impl NextScrollCursorCenterTopBottom {
 1160    fn next(&self) -> Self {
 1161        match self {
 1162            Self::Center => Self::Top,
 1163            Self::Top => Self::Bottom,
 1164            Self::Bottom => Self::Center,
 1165        }
 1166    }
 1167}
 1168
 1169#[derive(Clone)]
 1170pub struct EditorSnapshot {
 1171    pub mode: EditorMode,
 1172    show_gutter: bool,
 1173    show_line_numbers: Option<bool>,
 1174    show_git_diff_gutter: Option<bool>,
 1175    show_code_actions: Option<bool>,
 1176    show_runnables: Option<bool>,
 1177    show_breakpoints: Option<bool>,
 1178    git_blame_gutter_max_author_length: Option<usize>,
 1179    pub display_snapshot: DisplaySnapshot,
 1180    pub placeholder_text: Option<Arc<str>>,
 1181    is_focused: bool,
 1182    scroll_anchor: ScrollAnchor,
 1183    ongoing_scroll: OngoingScroll,
 1184    current_line_highlight: CurrentLineHighlight,
 1185    gutter_hovered: bool,
 1186}
 1187
 1188#[derive(Default, Debug, Clone, Copy)]
 1189pub struct GutterDimensions {
 1190    pub left_padding: Pixels,
 1191    pub right_padding: Pixels,
 1192    pub width: Pixels,
 1193    pub margin: Pixels,
 1194    pub git_blame_entries_width: Option<Pixels>,
 1195}
 1196
 1197impl GutterDimensions {
 1198    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1199        Self {
 1200            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1201            ..Default::default()
 1202        }
 1203    }
 1204
 1205    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1206        -cx.text_system().descent(font_id, font_size)
 1207    }
 1208    /// The full width of the space taken up by the gutter.
 1209    pub fn full_width(&self) -> Pixels {
 1210        self.margin + self.width
 1211    }
 1212
 1213    /// The width of the space reserved for the fold indicators,
 1214    /// use alongside 'justify_end' and `gutter_width` to
 1215    /// right align content with the line numbers
 1216    pub fn fold_area_width(&self) -> Pixels {
 1217        self.margin + self.right_padding
 1218    }
 1219}
 1220
 1221struct CharacterDimensions {
 1222    em_width: Pixels,
 1223    em_advance: Pixels,
 1224    line_height: Pixels,
 1225}
 1226
 1227#[derive(Debug)]
 1228pub struct RemoteSelection {
 1229    pub replica_id: ReplicaId,
 1230    pub selection: Selection<Anchor>,
 1231    pub cursor_shape: CursorShape,
 1232    pub collaborator_id: CollaboratorId,
 1233    pub line_mode: bool,
 1234    pub user_name: Option<SharedString>,
 1235    pub color: PlayerColor,
 1236}
 1237
 1238#[derive(Clone, Debug)]
 1239struct SelectionHistoryEntry {
 1240    selections: Arc<[Selection<Anchor>]>,
 1241    select_next_state: Option<SelectNextState>,
 1242    select_prev_state: Option<SelectNextState>,
 1243    add_selections_state: Option<AddSelectionsState>,
 1244}
 1245
 1246#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1247enum SelectionHistoryMode {
 1248    Normal,
 1249    Undoing,
 1250    Redoing,
 1251    Skipping,
 1252}
 1253
 1254#[derive(Clone, PartialEq, Eq, Hash)]
 1255struct HoveredCursor {
 1256    replica_id: u16,
 1257    selection_id: usize,
 1258}
 1259
 1260impl Default for SelectionHistoryMode {
 1261    fn default() -> Self {
 1262        Self::Normal
 1263    }
 1264}
 1265
 1266#[derive(Debug)]
 1267/// SelectionEffects controls the side-effects of updating the selection.
 1268///
 1269/// The default behaviour does "what you mostly want":
 1270/// - it pushes to the nav history if the cursor moved by >10 lines
 1271/// - it re-triggers completion requests
 1272/// - it scrolls to fit
 1273///
 1274/// You might want to modify these behaviours. For example when doing a "jump"
 1275/// like go to definition, we always want to add to nav history; but when scrolling
 1276/// in vim mode we never do.
 1277///
 1278/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1279/// move.
 1280pub struct SelectionEffects {
 1281    nav_history: Option<bool>,
 1282    completions: bool,
 1283    scroll: Option<Autoscroll>,
 1284}
 1285
 1286impl Default for SelectionEffects {
 1287    fn default() -> Self {
 1288        Self {
 1289            nav_history: None,
 1290            completions: true,
 1291            scroll: Some(Autoscroll::fit()),
 1292        }
 1293    }
 1294}
 1295impl SelectionEffects {
 1296    pub fn scroll(scroll: Autoscroll) -> Self {
 1297        Self {
 1298            scroll: Some(scroll),
 1299            ..Default::default()
 1300        }
 1301    }
 1302
 1303    pub fn no_scroll() -> Self {
 1304        Self {
 1305            scroll: None,
 1306            ..Default::default()
 1307        }
 1308    }
 1309
 1310    pub fn completions(self, completions: bool) -> Self {
 1311        Self {
 1312            completions,
 1313            ..self
 1314        }
 1315    }
 1316
 1317    pub fn nav_history(self, nav_history: bool) -> Self {
 1318        Self {
 1319            nav_history: Some(nav_history),
 1320            ..self
 1321        }
 1322    }
 1323}
 1324
 1325struct DeferredSelectionEffectsState {
 1326    changed: bool,
 1327    effects: SelectionEffects,
 1328    old_cursor_position: Anchor,
 1329    history_entry: SelectionHistoryEntry,
 1330}
 1331
 1332#[derive(Default)]
 1333struct SelectionHistory {
 1334    #[allow(clippy::type_complexity)]
 1335    selections_by_transaction:
 1336        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1337    mode: SelectionHistoryMode,
 1338    undo_stack: VecDeque<SelectionHistoryEntry>,
 1339    redo_stack: VecDeque<SelectionHistoryEntry>,
 1340}
 1341
 1342impl SelectionHistory {
 1343    #[track_caller]
 1344    fn insert_transaction(
 1345        &mut self,
 1346        transaction_id: TransactionId,
 1347        selections: Arc<[Selection<Anchor>]>,
 1348    ) {
 1349        if selections.is_empty() {
 1350            log::error!(
 1351                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1352                std::panic::Location::caller()
 1353            );
 1354            return;
 1355        }
 1356        self.selections_by_transaction
 1357            .insert(transaction_id, (selections, None));
 1358    }
 1359
 1360    #[allow(clippy::type_complexity)]
 1361    fn transaction(
 1362        &self,
 1363        transaction_id: TransactionId,
 1364    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1365        self.selections_by_transaction.get(&transaction_id)
 1366    }
 1367
 1368    #[allow(clippy::type_complexity)]
 1369    fn transaction_mut(
 1370        &mut self,
 1371        transaction_id: TransactionId,
 1372    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1373        self.selections_by_transaction.get_mut(&transaction_id)
 1374    }
 1375
 1376    fn push(&mut self, entry: SelectionHistoryEntry) {
 1377        if !entry.selections.is_empty() {
 1378            match self.mode {
 1379                SelectionHistoryMode::Normal => {
 1380                    self.push_undo(entry);
 1381                    self.redo_stack.clear();
 1382                }
 1383                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1384                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1385                SelectionHistoryMode::Skipping => {}
 1386            }
 1387        }
 1388    }
 1389
 1390    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1391        if self
 1392            .undo_stack
 1393            .back()
 1394            .map_or(true, |e| e.selections != entry.selections)
 1395        {
 1396            self.undo_stack.push_back(entry);
 1397            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1398                self.undo_stack.pop_front();
 1399            }
 1400        }
 1401    }
 1402
 1403    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1404        if self
 1405            .redo_stack
 1406            .back()
 1407            .map_or(true, |e| e.selections != entry.selections)
 1408        {
 1409            self.redo_stack.push_back(entry);
 1410            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1411                self.redo_stack.pop_front();
 1412            }
 1413        }
 1414    }
 1415}
 1416
 1417#[derive(Clone, Copy)]
 1418pub struct RowHighlightOptions {
 1419    pub autoscroll: bool,
 1420    pub include_gutter: bool,
 1421}
 1422
 1423impl Default for RowHighlightOptions {
 1424    fn default() -> Self {
 1425        Self {
 1426            autoscroll: Default::default(),
 1427            include_gutter: true,
 1428        }
 1429    }
 1430}
 1431
 1432struct RowHighlight {
 1433    index: usize,
 1434    range: Range<Anchor>,
 1435    color: Hsla,
 1436    options: RowHighlightOptions,
 1437    type_id: TypeId,
 1438}
 1439
 1440#[derive(Clone, Debug)]
 1441struct AddSelectionsState {
 1442    groups: Vec<AddSelectionsGroup>,
 1443}
 1444
 1445#[derive(Clone, Debug)]
 1446struct AddSelectionsGroup {
 1447    above: bool,
 1448    stack: Vec<usize>,
 1449}
 1450
 1451#[derive(Clone)]
 1452struct SelectNextState {
 1453    query: AhoCorasick,
 1454    wordwise: bool,
 1455    done: bool,
 1456}
 1457
 1458impl std::fmt::Debug for SelectNextState {
 1459    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1460        f.debug_struct(std::any::type_name::<Self>())
 1461            .field("wordwise", &self.wordwise)
 1462            .field("done", &self.done)
 1463            .finish()
 1464    }
 1465}
 1466
 1467#[derive(Debug)]
 1468struct AutocloseRegion {
 1469    selection_id: usize,
 1470    range: Range<Anchor>,
 1471    pair: BracketPair,
 1472}
 1473
 1474#[derive(Debug)]
 1475struct SnippetState {
 1476    ranges: Vec<Vec<Range<Anchor>>>,
 1477    active_index: usize,
 1478    choices: Vec<Option<Vec<String>>>,
 1479}
 1480
 1481#[doc(hidden)]
 1482pub struct RenameState {
 1483    pub range: Range<Anchor>,
 1484    pub old_name: Arc<str>,
 1485    pub editor: Entity<Editor>,
 1486    block_id: CustomBlockId,
 1487}
 1488
 1489struct InvalidationStack<T>(Vec<T>);
 1490
 1491struct RegisteredInlineCompletionProvider {
 1492    provider: Arc<dyn InlineCompletionProviderHandle>,
 1493    _subscription: Subscription,
 1494}
 1495
 1496#[derive(Debug, PartialEq, Eq)]
 1497pub struct ActiveDiagnosticGroup {
 1498    pub active_range: Range<Anchor>,
 1499    pub active_message: String,
 1500    pub group_id: usize,
 1501    pub blocks: HashSet<CustomBlockId>,
 1502}
 1503
 1504#[derive(Debug, PartialEq, Eq)]
 1505
 1506pub(crate) enum ActiveDiagnostic {
 1507    None,
 1508    All,
 1509    Group(ActiveDiagnosticGroup),
 1510}
 1511
 1512#[derive(Serialize, Deserialize, Clone, Debug)]
 1513pub struct ClipboardSelection {
 1514    /// The number of bytes in this selection.
 1515    pub len: usize,
 1516    /// Whether this was a full-line selection.
 1517    pub is_entire_line: bool,
 1518    /// The indentation of the first line when this content was originally copied.
 1519    pub first_line_indent: u32,
 1520}
 1521
 1522// selections, scroll behavior, was newest selection reversed
 1523type SelectSyntaxNodeHistoryState = (
 1524    Box<[Selection<usize>]>,
 1525    SelectSyntaxNodeScrollBehavior,
 1526    bool,
 1527);
 1528
 1529#[derive(Default)]
 1530struct SelectSyntaxNodeHistory {
 1531    stack: Vec<SelectSyntaxNodeHistoryState>,
 1532    // disable temporarily to allow changing selections without losing the stack
 1533    pub disable_clearing: bool,
 1534}
 1535
 1536impl SelectSyntaxNodeHistory {
 1537    pub fn try_clear(&mut self) {
 1538        if !self.disable_clearing {
 1539            self.stack.clear();
 1540        }
 1541    }
 1542
 1543    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1544        self.stack.push(selection);
 1545    }
 1546
 1547    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1548        self.stack.pop()
 1549    }
 1550}
 1551
 1552enum SelectSyntaxNodeScrollBehavior {
 1553    CursorTop,
 1554    FitSelection,
 1555    CursorBottom,
 1556}
 1557
 1558#[derive(Debug)]
 1559pub(crate) struct NavigationData {
 1560    cursor_anchor: Anchor,
 1561    cursor_position: Point,
 1562    scroll_anchor: ScrollAnchor,
 1563    scroll_top_row: u32,
 1564}
 1565
 1566#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1567pub enum GotoDefinitionKind {
 1568    Symbol,
 1569    Declaration,
 1570    Type,
 1571    Implementation,
 1572}
 1573
 1574#[derive(Debug, Clone)]
 1575enum InlayHintRefreshReason {
 1576    ModifiersChanged(bool),
 1577    Toggle(bool),
 1578    SettingsChange(InlayHintSettings),
 1579    NewLinesShown,
 1580    BufferEdited(HashSet<Arc<Language>>),
 1581    RefreshRequested,
 1582    ExcerptsRemoved(Vec<ExcerptId>),
 1583}
 1584
 1585impl InlayHintRefreshReason {
 1586    fn description(&self) -> &'static str {
 1587        match self {
 1588            Self::ModifiersChanged(_) => "modifiers changed",
 1589            Self::Toggle(_) => "toggle",
 1590            Self::SettingsChange(_) => "settings change",
 1591            Self::NewLinesShown => "new lines shown",
 1592            Self::BufferEdited(_) => "buffer edited",
 1593            Self::RefreshRequested => "refresh requested",
 1594            Self::ExcerptsRemoved(_) => "excerpts removed",
 1595        }
 1596    }
 1597}
 1598
 1599pub enum FormatTarget {
 1600    Buffers(HashSet<Entity<Buffer>>),
 1601    Ranges(Vec<Range<MultiBufferPoint>>),
 1602}
 1603
 1604pub(crate) struct FocusedBlock {
 1605    id: BlockId,
 1606    focus_handle: WeakFocusHandle,
 1607}
 1608
 1609#[derive(Clone)]
 1610enum JumpData {
 1611    MultiBufferRow {
 1612        row: MultiBufferRow,
 1613        line_offset_from_top: u32,
 1614    },
 1615    MultiBufferPoint {
 1616        excerpt_id: ExcerptId,
 1617        position: Point,
 1618        anchor: text::Anchor,
 1619        line_offset_from_top: u32,
 1620    },
 1621}
 1622
 1623pub enum MultibufferSelectionMode {
 1624    First,
 1625    All,
 1626}
 1627
 1628#[derive(Clone, Copy, Debug, Default)]
 1629pub struct RewrapOptions {
 1630    pub override_language_settings: bool,
 1631    pub preserve_existing_whitespace: bool,
 1632}
 1633
 1634impl Editor {
 1635    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1636        let buffer = cx.new(|cx| Buffer::local("", cx));
 1637        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1638        Self::new(
 1639            EditorMode::SingleLine { auto_width: false },
 1640            buffer,
 1641            None,
 1642            window,
 1643            cx,
 1644        )
 1645    }
 1646
 1647    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1648        let buffer = cx.new(|cx| Buffer::local("", cx));
 1649        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1650        Self::new(EditorMode::full(), buffer, None, window, cx)
 1651    }
 1652
 1653    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1654        let buffer = cx.new(|cx| Buffer::local("", cx));
 1655        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1656        Self::new(
 1657            EditorMode::SingleLine { auto_width: true },
 1658            buffer,
 1659            None,
 1660            window,
 1661            cx,
 1662        )
 1663    }
 1664
 1665    pub fn auto_height(
 1666        min_lines: usize,
 1667        max_lines: usize,
 1668        window: &mut Window,
 1669        cx: &mut Context<Self>,
 1670    ) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(
 1674            EditorMode::AutoHeight {
 1675                min_lines,
 1676                max_lines: Some(max_lines),
 1677            },
 1678            buffer,
 1679            None,
 1680            window,
 1681            cx,
 1682        )
 1683    }
 1684
 1685    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1686    /// The editor grows as tall as needed to fit its content.
 1687    pub fn auto_height_unbounded(
 1688        min_lines: usize,
 1689        window: &mut Window,
 1690        cx: &mut Context<Self>,
 1691    ) -> Self {
 1692        let buffer = cx.new(|cx| Buffer::local("", cx));
 1693        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1694        Self::new(
 1695            EditorMode::AutoHeight {
 1696                min_lines,
 1697                max_lines: None,
 1698            },
 1699            buffer,
 1700            None,
 1701            window,
 1702            cx,
 1703        )
 1704    }
 1705
 1706    pub fn for_buffer(
 1707        buffer: Entity<Buffer>,
 1708        project: Option<Entity<Project>>,
 1709        window: &mut Window,
 1710        cx: &mut Context<Self>,
 1711    ) -> Self {
 1712        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1713        Self::new(EditorMode::full(), buffer, project, window, cx)
 1714    }
 1715
 1716    pub fn for_multibuffer(
 1717        buffer: Entity<MultiBuffer>,
 1718        project: Option<Entity<Project>>,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        Self::new(EditorMode::full(), buffer, project, window, cx)
 1723    }
 1724
 1725    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1726        let mut clone = Self::new(
 1727            self.mode.clone(),
 1728            self.buffer.clone(),
 1729            self.project.clone(),
 1730            window,
 1731            cx,
 1732        );
 1733        self.display_map.update(cx, |display_map, cx| {
 1734            let snapshot = display_map.snapshot(cx);
 1735            clone.display_map.update(cx, |display_map, cx| {
 1736                display_map.set_state(&snapshot, cx);
 1737            });
 1738        });
 1739        clone.folds_did_change(cx);
 1740        clone.selections.clone_state(&self.selections);
 1741        clone.scroll_manager.clone_state(&self.scroll_manager);
 1742        clone.searchable = self.searchable;
 1743        clone.read_only = self.read_only;
 1744        clone
 1745    }
 1746
 1747    pub fn new(
 1748        mode: EditorMode,
 1749        buffer: Entity<MultiBuffer>,
 1750        project: Option<Entity<Project>>,
 1751        window: &mut Window,
 1752        cx: &mut Context<Self>,
 1753    ) -> Self {
 1754        Editor::new_internal(mode, buffer, project, None, window, cx)
 1755    }
 1756
 1757    fn new_internal(
 1758        mode: EditorMode,
 1759        buffer: Entity<MultiBuffer>,
 1760        project: Option<Entity<Project>>,
 1761        display_map: Option<Entity<DisplayMap>>,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        debug_assert!(
 1766            display_map.is_none() || mode.is_minimap(),
 1767            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1768        );
 1769
 1770        let full_mode = mode.is_full();
 1771        let diagnostics_max_severity = if full_mode {
 1772            EditorSettings::get_global(cx)
 1773                .diagnostics_max_severity
 1774                .unwrap_or(DiagnosticSeverity::Hint)
 1775        } else {
 1776            DiagnosticSeverity::Off
 1777        };
 1778        let style = window.text_style();
 1779        let font_size = style.font_size.to_pixels(window.rem_size());
 1780        let editor = cx.entity().downgrade();
 1781        let fold_placeholder = FoldPlaceholder {
 1782            constrain_width: true,
 1783            render: Arc::new(move |fold_id, fold_range, cx| {
 1784                let editor = editor.clone();
 1785                div()
 1786                    .id(fold_id)
 1787                    .bg(cx.theme().colors().ghost_element_background)
 1788                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1789                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1790                    .rounded_xs()
 1791                    .size_full()
 1792                    .cursor_pointer()
 1793                    .child("")
 1794                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1795                    .on_click(move |_, _window, cx| {
 1796                        editor
 1797                            .update(cx, |editor, cx| {
 1798                                editor.unfold_ranges(
 1799                                    &[fold_range.start..fold_range.end],
 1800                                    true,
 1801                                    false,
 1802                                    cx,
 1803                                );
 1804                                cx.stop_propagation();
 1805                            })
 1806                            .ok();
 1807                    })
 1808                    .into_any()
 1809            }),
 1810            merge_adjacent: true,
 1811            ..FoldPlaceholder::default()
 1812        };
 1813        let display_map = display_map.unwrap_or_else(|| {
 1814            cx.new(|cx| {
 1815                DisplayMap::new(
 1816                    buffer.clone(),
 1817                    style.font(),
 1818                    font_size,
 1819                    None,
 1820                    FILE_HEADER_HEIGHT,
 1821                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1822                    fold_placeholder,
 1823                    diagnostics_max_severity,
 1824                    cx,
 1825                )
 1826            })
 1827        });
 1828
 1829        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1830
 1831        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1832
 1833        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1834            .then(|| language_settings::SoftWrap::None);
 1835
 1836        let mut project_subscriptions = Vec::new();
 1837        if mode.is_full() {
 1838            if let Some(project) = project.as_ref() {
 1839                project_subscriptions.push(cx.subscribe_in(
 1840                    project,
 1841                    window,
 1842                    |editor, _, event, window, cx| match event {
 1843                        project::Event::RefreshCodeLens => {
 1844                            // we always query lens with actions, without storing them, always refreshing them
 1845                        }
 1846                        project::Event::RefreshInlayHints => {
 1847                            editor
 1848                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1849                        }
 1850                        project::Event::LanguageServerAdded(..)
 1851                        | project::Event::LanguageServerRemoved(..) => {
 1852                            if editor.tasks_update_task.is_none() {
 1853                                editor.tasks_update_task =
 1854                                    Some(editor.refresh_runnables(window, cx));
 1855                            }
 1856                            editor.update_lsp_data(true, None, window, cx);
 1857                        }
 1858                        project::Event::SnippetEdit(id, snippet_edits) => {
 1859                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1860                                let focus_handle = editor.focus_handle(cx);
 1861                                if focus_handle.is_focused(window) {
 1862                                    let snapshot = buffer.read(cx).snapshot();
 1863                                    for (range, snippet) in snippet_edits {
 1864                                        let editor_range =
 1865                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1866                                        editor
 1867                                            .insert_snippet(
 1868                                                &[editor_range],
 1869                                                snippet.clone(),
 1870                                                window,
 1871                                                cx,
 1872                                            )
 1873                                            .ok();
 1874                                    }
 1875                                }
 1876                            }
 1877                        }
 1878                        _ => {}
 1879                    },
 1880                ));
 1881                if let Some(task_inventory) = project
 1882                    .read(cx)
 1883                    .task_store()
 1884                    .read(cx)
 1885                    .task_inventory()
 1886                    .cloned()
 1887                {
 1888                    project_subscriptions.push(cx.observe_in(
 1889                        &task_inventory,
 1890                        window,
 1891                        |editor, _, window, cx| {
 1892                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1893                        },
 1894                    ));
 1895                };
 1896
 1897                project_subscriptions.push(cx.subscribe_in(
 1898                    &project.read(cx).breakpoint_store(),
 1899                    window,
 1900                    |editor, _, event, window, cx| match event {
 1901                        BreakpointStoreEvent::ClearDebugLines => {
 1902                            editor.clear_row_highlights::<ActiveDebugLine>();
 1903                            editor.refresh_inline_values(cx);
 1904                        }
 1905                        BreakpointStoreEvent::SetDebugLine => {
 1906                            if editor.go_to_active_debug_line(window, cx) {
 1907                                cx.stop_propagation();
 1908                            }
 1909
 1910                            editor.refresh_inline_values(cx);
 1911                        }
 1912                        _ => {}
 1913                    },
 1914                ));
 1915                let git_store = project.read(cx).git_store().clone();
 1916                let project = project.clone();
 1917                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1918                    match event {
 1919                        GitStoreEvent::RepositoryUpdated(
 1920                            _,
 1921                            RepositoryEvent::Updated {
 1922                                new_instance: true, ..
 1923                            },
 1924                            _,
 1925                        ) => {
 1926                            this.load_diff_task = Some(
 1927                                update_uncommitted_diff_for_buffer(
 1928                                    cx.entity(),
 1929                                    &project,
 1930                                    this.buffer.read(cx).all_buffers(),
 1931                                    this.buffer.clone(),
 1932                                    cx,
 1933                                )
 1934                                .shared(),
 1935                            );
 1936                        }
 1937                        _ => {}
 1938                    }
 1939                }));
 1940            }
 1941        }
 1942
 1943        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1944
 1945        let inlay_hint_settings =
 1946            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1947        let focus_handle = cx.focus_handle();
 1948        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1949            .detach();
 1950        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1951            .detach();
 1952        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1953            .detach();
 1954        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1955            .detach();
 1956        cx.observe_pending_input(window, Self::observe_pending_input)
 1957            .detach();
 1958
 1959        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1960            Some(false)
 1961        } else {
 1962            None
 1963        };
 1964
 1965        let breakpoint_store = match (&mode, project.as_ref()) {
 1966            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1967            _ => None,
 1968        };
 1969
 1970        let mut code_action_providers = Vec::new();
 1971        let mut load_uncommitted_diff = None;
 1972        if let Some(project) = project.clone() {
 1973            load_uncommitted_diff = Some(
 1974                update_uncommitted_diff_for_buffer(
 1975                    cx.entity(),
 1976                    &project,
 1977                    buffer.read(cx).all_buffers(),
 1978                    buffer.clone(),
 1979                    cx,
 1980                )
 1981                .shared(),
 1982            );
 1983            code_action_providers.push(Rc::new(project) as Rc<_>);
 1984        }
 1985
 1986        let mut editor = Self {
 1987            focus_handle,
 1988            show_cursor_when_unfocused: false,
 1989            last_focused_descendant: None,
 1990            buffer: buffer.clone(),
 1991            display_map: display_map.clone(),
 1992            selections,
 1993            scroll_manager: ScrollManager::new(cx),
 1994            columnar_selection_state: None,
 1995            add_selections_state: None,
 1996            select_next_state: None,
 1997            select_prev_state: None,
 1998            selection_history: SelectionHistory::default(),
 1999            defer_selection_effects: false,
 2000            deferred_selection_effects_state: None,
 2001            autoclose_regions: Vec::new(),
 2002            snippet_stack: InvalidationStack::default(),
 2003            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2004            ime_transaction: None,
 2005            active_diagnostics: ActiveDiagnostic::None,
 2006            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2007            inline_diagnostics_update: Task::ready(()),
 2008            inline_diagnostics: Vec::new(),
 2009            soft_wrap_mode_override,
 2010            diagnostics_max_severity,
 2011            hard_wrap: None,
 2012            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2013            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2014            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2015            project,
 2016            blink_manager: blink_manager.clone(),
 2017            show_local_selections: true,
 2018            show_scrollbars: ScrollbarAxes {
 2019                horizontal: full_mode,
 2020                vertical: full_mode,
 2021            },
 2022            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2023            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2024            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2025            show_gutter: mode.is_full(),
 2026            show_line_numbers: None,
 2027            use_relative_line_numbers: None,
 2028            disable_expand_excerpt_buttons: false,
 2029            show_git_diff_gutter: None,
 2030            show_code_actions: None,
 2031            show_runnables: None,
 2032            show_breakpoints: None,
 2033            show_wrap_guides: None,
 2034            show_indent_guides,
 2035            placeholder_text: None,
 2036            highlight_order: 0,
 2037            highlighted_rows: HashMap::default(),
 2038            background_highlights: TreeMap::default(),
 2039            gutter_highlights: TreeMap::default(),
 2040            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2041            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2042            nav_history: None,
 2043            context_menu: RefCell::new(None),
 2044            context_menu_options: None,
 2045            mouse_context_menu: None,
 2046            completion_tasks: Vec::new(),
 2047            inline_blame_popover: None,
 2048            inline_blame_popover_show_task: None,
 2049            signature_help_state: SignatureHelpState::default(),
 2050            auto_signature_help: None,
 2051            find_all_references_task_sources: Vec::new(),
 2052            next_completion_id: 0,
 2053            next_inlay_id: 0,
 2054            code_action_providers,
 2055            available_code_actions: None,
 2056            code_actions_task: None,
 2057            quick_selection_highlight_task: None,
 2058            debounced_selection_highlight_task: None,
 2059            document_highlights_task: None,
 2060            linked_editing_range_task: None,
 2061            pending_rename: None,
 2062            searchable: true,
 2063            cursor_shape: EditorSettings::get_global(cx)
 2064                .cursor_shape
 2065                .unwrap_or_default(),
 2066            current_line_highlight: None,
 2067            autoindent_mode: Some(AutoindentMode::EachLine),
 2068            collapse_matches: false,
 2069            workspace: None,
 2070            input_enabled: true,
 2071            use_modal_editing: mode.is_full(),
 2072            read_only: mode.is_minimap(),
 2073            use_autoclose: true,
 2074            use_auto_surround: true,
 2075            auto_replace_emoji_shortcode: false,
 2076            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2077            leader_id: None,
 2078            remote_id: None,
 2079            hover_state: HoverState::default(),
 2080            pending_mouse_down: None,
 2081            hovered_link_state: None,
 2082            edit_prediction_provider: None,
 2083            active_inline_completion: None,
 2084            stale_inline_completion_in_menu: None,
 2085            edit_prediction_preview: EditPredictionPreview::Inactive {
 2086                released_too_fast: false,
 2087            },
 2088            inline_diagnostics_enabled: mode.is_full(),
 2089            diagnostics_enabled: mode.is_full(),
 2090            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2091            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2092
 2093            gutter_hovered: false,
 2094            pixel_position_of_newest_cursor: None,
 2095            last_bounds: None,
 2096            last_position_map: None,
 2097            expect_bounds_change: None,
 2098            gutter_dimensions: GutterDimensions::default(),
 2099            style: None,
 2100            show_cursor_names: false,
 2101            hovered_cursors: HashMap::default(),
 2102            next_editor_action_id: EditorActionId::default(),
 2103            editor_actions: Rc::default(),
 2104            inline_completions_hidden_for_vim_mode: false,
 2105            show_inline_completions_override: None,
 2106            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2107            edit_prediction_settings: EditPredictionSettings::Disabled,
 2108            edit_prediction_indent_conflict: false,
 2109            edit_prediction_requires_modifier_in_indent_conflict: true,
 2110            custom_context_menu: None,
 2111            show_git_blame_gutter: false,
 2112            show_git_blame_inline: false,
 2113            show_selection_menu: None,
 2114            show_git_blame_inline_delay_task: None,
 2115            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2116            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2117            serialize_dirty_buffers: !mode.is_minimap()
 2118                && ProjectSettings::get_global(cx)
 2119                    .session
 2120                    .restore_unsaved_buffers,
 2121            blame: None,
 2122            blame_subscription: None,
 2123            tasks: BTreeMap::default(),
 2124
 2125            breakpoint_store,
 2126            gutter_breakpoint_indicator: (None, None),
 2127            hovered_diff_hunk_row: None,
 2128            _subscriptions: vec![
 2129                cx.observe(&buffer, Self::on_buffer_changed),
 2130                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2131                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2132                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2133                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2134                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2135                cx.observe_window_activation(window, |editor, window, cx| {
 2136                    let active = window.is_window_active();
 2137                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2138                        if active {
 2139                            blink_manager.enable(cx);
 2140                        } else {
 2141                            blink_manager.disable(cx);
 2142                        }
 2143                    });
 2144                    if active {
 2145                        editor.show_mouse_cursor(cx);
 2146                    }
 2147                }),
 2148            ],
 2149            tasks_update_task: None,
 2150            pull_diagnostics_task: Task::ready(()),
 2151            colors: None,
 2152            next_color_inlay_id: 0,
 2153            linked_edit_ranges: Default::default(),
 2154            in_project_search: false,
 2155            previous_search_ranges: None,
 2156            breadcrumb_header: None,
 2157            focused_block: None,
 2158            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2159            addons: HashMap::default(),
 2160            registered_buffers: HashMap::default(),
 2161            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2162            selection_mark_mode: false,
 2163            toggle_fold_multiple_buffers: Task::ready(()),
 2164            serialize_selections: Task::ready(()),
 2165            serialize_folds: Task::ready(()),
 2166            text_style_refinement: None,
 2167            load_diff_task: load_uncommitted_diff,
 2168            temporary_diff_override: false,
 2169            mouse_cursor_hidden: false,
 2170            minimap: None,
 2171            hide_mouse_mode: EditorSettings::get_global(cx)
 2172                .hide_mouse
 2173                .unwrap_or_default(),
 2174            change_list: ChangeList::new(),
 2175            mode,
 2176            selection_drag_state: SelectionDragState::None,
 2177            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2178            folding_newlines: Task::ready(()),
 2179        };
 2180        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2181            editor
 2182                ._subscriptions
 2183                .push(cx.observe(breakpoints, |_, _, cx| {
 2184                    cx.notify();
 2185                }));
 2186        }
 2187        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2188        editor._subscriptions.extend(project_subscriptions);
 2189
 2190        editor._subscriptions.push(cx.subscribe_in(
 2191            &cx.entity(),
 2192            window,
 2193            |editor, _, e: &EditorEvent, window, cx| match e {
 2194                EditorEvent::ScrollPositionChanged { local, .. } => {
 2195                    if *local {
 2196                        let new_anchor = editor.scroll_manager.anchor();
 2197                        let snapshot = editor.snapshot(window, cx);
 2198                        editor.update_restoration_data(cx, move |data| {
 2199                            data.scroll_position = (
 2200                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2201                                new_anchor.offset,
 2202                            );
 2203                        });
 2204                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2205                        editor.inline_blame_popover.take();
 2206                    }
 2207                }
 2208                EditorEvent::Edited { .. } => {
 2209                    if !vim_enabled(cx) {
 2210                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2211                        let pop_state = editor
 2212                            .change_list
 2213                            .last()
 2214                            .map(|previous| {
 2215                                previous.len() == selections.len()
 2216                                    && previous.iter().enumerate().all(|(ix, p)| {
 2217                                        p.to_display_point(&map).row()
 2218                                            == selections[ix].head().row()
 2219                                    })
 2220                            })
 2221                            .unwrap_or(false);
 2222                        let new_positions = selections
 2223                            .into_iter()
 2224                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2225                            .collect();
 2226                        editor
 2227                            .change_list
 2228                            .push_to_change_list(pop_state, new_positions);
 2229                    }
 2230                }
 2231                _ => (),
 2232            },
 2233        ));
 2234
 2235        if let Some(dap_store) = editor
 2236            .project
 2237            .as_ref()
 2238            .map(|project| project.read(cx).dap_store())
 2239        {
 2240            let weak_editor = cx.weak_entity();
 2241
 2242            editor
 2243                ._subscriptions
 2244                .push(
 2245                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2246                        let session_entity = cx.entity();
 2247                        weak_editor
 2248                            .update(cx, |editor, cx| {
 2249                                editor._subscriptions.push(
 2250                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2251                                );
 2252                            })
 2253                            .ok();
 2254                    }),
 2255                );
 2256
 2257            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2258                editor
 2259                    ._subscriptions
 2260                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2261            }
 2262        }
 2263
 2264        // skip adding the initial selection to selection history
 2265        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2266        editor.end_selection(window, cx);
 2267        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2268
 2269        editor.scroll_manager.show_scrollbars(window, cx);
 2270        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2271
 2272        if full_mode {
 2273            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2274            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2275
 2276            if editor.git_blame_inline_enabled {
 2277                editor.start_git_blame_inline(false, window, cx);
 2278            }
 2279
 2280            editor.go_to_active_debug_line(window, cx);
 2281
 2282            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2283                if let Some(project) = editor.project.as_ref() {
 2284                    let handle = project.update(cx, |project, cx| {
 2285                        project.register_buffer_with_language_servers(&buffer, cx)
 2286                    });
 2287                    editor
 2288                        .registered_buffers
 2289                        .insert(buffer.read(cx).remote_id(), handle);
 2290                }
 2291            }
 2292
 2293            editor.minimap =
 2294                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2295            editor.colors = Some(LspColorData::new(cx));
 2296            editor.update_lsp_data(false, None, window, cx);
 2297        }
 2298
 2299        editor.report_editor_event("Editor Opened", None, cx);
 2300        editor
 2301    }
 2302
 2303    pub fn deploy_mouse_context_menu(
 2304        &mut self,
 2305        position: gpui::Point<Pixels>,
 2306        context_menu: Entity<ContextMenu>,
 2307        window: &mut Window,
 2308        cx: &mut Context<Self>,
 2309    ) {
 2310        self.mouse_context_menu = Some(MouseContextMenu::new(
 2311            self,
 2312            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2313            context_menu,
 2314            window,
 2315            cx,
 2316        ));
 2317    }
 2318
 2319    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2320        self.mouse_context_menu
 2321            .as_ref()
 2322            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2323    }
 2324
 2325    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2326        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2327    }
 2328
 2329    fn key_context_internal(
 2330        &self,
 2331        has_active_edit_prediction: bool,
 2332        window: &Window,
 2333        cx: &App,
 2334    ) -> KeyContext {
 2335        let mut key_context = KeyContext::new_with_defaults();
 2336        key_context.add("Editor");
 2337        let mode = match self.mode {
 2338            EditorMode::SingleLine { .. } => "single_line",
 2339            EditorMode::AutoHeight { .. } => "auto_height",
 2340            EditorMode::Minimap { .. } => "minimap",
 2341            EditorMode::Full { .. } => "full",
 2342        };
 2343
 2344        if EditorSettings::jupyter_enabled(cx) {
 2345            key_context.add("jupyter");
 2346        }
 2347
 2348        key_context.set("mode", mode);
 2349        if self.pending_rename.is_some() {
 2350            key_context.add("renaming");
 2351        }
 2352
 2353        match self.context_menu.borrow().as_ref() {
 2354            Some(CodeContextMenu::Completions(_)) => {
 2355                key_context.add("menu");
 2356                key_context.add("showing_completions");
 2357            }
 2358            Some(CodeContextMenu::CodeActions(_)) => {
 2359                key_context.add("menu");
 2360                key_context.add("showing_code_actions")
 2361            }
 2362            None => {}
 2363        }
 2364
 2365        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2366        if !self.focus_handle(cx).contains_focused(window, cx)
 2367            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2368        {
 2369            for addon in self.addons.values() {
 2370                addon.extend_key_context(&mut key_context, cx)
 2371            }
 2372        }
 2373
 2374        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2375            if let Some(extension) = singleton_buffer
 2376                .read(cx)
 2377                .file()
 2378                .and_then(|file| file.path().extension()?.to_str())
 2379            {
 2380                key_context.set("extension", extension.to_string());
 2381            }
 2382        } else {
 2383            key_context.add("multibuffer");
 2384        }
 2385
 2386        if has_active_edit_prediction {
 2387            if self.edit_prediction_in_conflict() {
 2388                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2389            } else {
 2390                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2391                key_context.add("copilot_suggestion");
 2392            }
 2393        }
 2394
 2395        if self.selection_mark_mode {
 2396            key_context.add("selection_mode");
 2397        }
 2398
 2399        key_context
 2400    }
 2401
 2402    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2403        if self.mouse_cursor_hidden {
 2404            self.mouse_cursor_hidden = false;
 2405            cx.notify();
 2406        }
 2407    }
 2408
 2409    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2410        let hide_mouse_cursor = match origin {
 2411            HideMouseCursorOrigin::TypingAction => {
 2412                matches!(
 2413                    self.hide_mouse_mode,
 2414                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2415                )
 2416            }
 2417            HideMouseCursorOrigin::MovementAction => {
 2418                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2419            }
 2420        };
 2421        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2422            self.mouse_cursor_hidden = hide_mouse_cursor;
 2423            cx.notify();
 2424        }
 2425    }
 2426
 2427    pub fn edit_prediction_in_conflict(&self) -> bool {
 2428        if !self.show_edit_predictions_in_menu() {
 2429            return false;
 2430        }
 2431
 2432        let showing_completions = self
 2433            .context_menu
 2434            .borrow()
 2435            .as_ref()
 2436            .map_or(false, |context| {
 2437                matches!(context, CodeContextMenu::Completions(_))
 2438            });
 2439
 2440        showing_completions
 2441            || self.edit_prediction_requires_modifier()
 2442            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2443            // bindings to insert tab characters.
 2444            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2445    }
 2446
 2447    pub fn accept_edit_prediction_keybind(
 2448        &self,
 2449        accept_partial: bool,
 2450        window: &Window,
 2451        cx: &App,
 2452    ) -> AcceptEditPredictionBinding {
 2453        let key_context = self.key_context_internal(true, window, cx);
 2454        let in_conflict = self.edit_prediction_in_conflict();
 2455
 2456        let bindings = if accept_partial {
 2457            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2458        } else {
 2459            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2460        };
 2461
 2462        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2463        // just the first one.
 2464        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2465            !in_conflict
 2466                || binding
 2467                    .keystrokes()
 2468                    .first()
 2469                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2470        }))
 2471    }
 2472
 2473    pub fn new_file(
 2474        workspace: &mut Workspace,
 2475        _: &workspace::NewFile,
 2476        window: &mut Window,
 2477        cx: &mut Context<Workspace>,
 2478    ) {
 2479        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2480            "Failed to create buffer",
 2481            window,
 2482            cx,
 2483            |e, _, _| match e.error_code() {
 2484                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2485                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2486                e.error_tag("required").unwrap_or("the latest version")
 2487            )),
 2488                _ => None,
 2489            },
 2490        );
 2491    }
 2492
 2493    pub fn new_in_workspace(
 2494        workspace: &mut Workspace,
 2495        window: &mut Window,
 2496        cx: &mut Context<Workspace>,
 2497    ) -> Task<Result<Entity<Editor>>> {
 2498        let project = workspace.project().clone();
 2499        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2500
 2501        cx.spawn_in(window, async move |workspace, cx| {
 2502            let buffer = create.await?;
 2503            workspace.update_in(cx, |workspace, window, cx| {
 2504                let editor =
 2505                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2506                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2507                editor
 2508            })
 2509        })
 2510    }
 2511
 2512    fn new_file_vertical(
 2513        workspace: &mut Workspace,
 2514        _: &workspace::NewFileSplitVertical,
 2515        window: &mut Window,
 2516        cx: &mut Context<Workspace>,
 2517    ) {
 2518        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2519    }
 2520
 2521    fn new_file_horizontal(
 2522        workspace: &mut Workspace,
 2523        _: &workspace::NewFileSplitHorizontal,
 2524        window: &mut Window,
 2525        cx: &mut Context<Workspace>,
 2526    ) {
 2527        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2528    }
 2529
 2530    fn new_file_in_direction(
 2531        workspace: &mut Workspace,
 2532        direction: SplitDirection,
 2533        window: &mut Window,
 2534        cx: &mut Context<Workspace>,
 2535    ) {
 2536        let project = workspace.project().clone();
 2537        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2538
 2539        cx.spawn_in(window, async move |workspace, cx| {
 2540            let buffer = create.await?;
 2541            workspace.update_in(cx, move |workspace, window, cx| {
 2542                workspace.split_item(
 2543                    direction,
 2544                    Box::new(
 2545                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2546                    ),
 2547                    window,
 2548                    cx,
 2549                )
 2550            })?;
 2551            anyhow::Ok(())
 2552        })
 2553        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2554            match e.error_code() {
 2555                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2556                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2557                e.error_tag("required").unwrap_or("the latest version")
 2558            )),
 2559                _ => None,
 2560            }
 2561        });
 2562    }
 2563
 2564    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2565        self.leader_id
 2566    }
 2567
 2568    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2569        &self.buffer
 2570    }
 2571
 2572    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2573        self.workspace.as_ref()?.0.upgrade()
 2574    }
 2575
 2576    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2577        self.buffer().read(cx).title(cx)
 2578    }
 2579
 2580    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2581        let git_blame_gutter_max_author_length = self
 2582            .render_git_blame_gutter(cx)
 2583            .then(|| {
 2584                if let Some(blame) = self.blame.as_ref() {
 2585                    let max_author_length =
 2586                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2587                    Some(max_author_length)
 2588                } else {
 2589                    None
 2590                }
 2591            })
 2592            .flatten();
 2593
 2594        EditorSnapshot {
 2595            mode: self.mode.clone(),
 2596            show_gutter: self.show_gutter,
 2597            show_line_numbers: self.show_line_numbers,
 2598            show_git_diff_gutter: self.show_git_diff_gutter,
 2599            show_code_actions: self.show_code_actions,
 2600            show_runnables: self.show_runnables,
 2601            show_breakpoints: self.show_breakpoints,
 2602            git_blame_gutter_max_author_length,
 2603            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2604            scroll_anchor: self.scroll_manager.anchor(),
 2605            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2606            placeholder_text: self.placeholder_text.clone(),
 2607            is_focused: self.focus_handle.is_focused(window),
 2608            current_line_highlight: self
 2609                .current_line_highlight
 2610                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2611            gutter_hovered: self.gutter_hovered,
 2612        }
 2613    }
 2614
 2615    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2616        self.buffer.read(cx).language_at(point, cx)
 2617    }
 2618
 2619    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2620        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2621    }
 2622
 2623    pub fn active_excerpt(
 2624        &self,
 2625        cx: &App,
 2626    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2627        self.buffer
 2628            .read(cx)
 2629            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2630    }
 2631
 2632    pub fn mode(&self) -> &EditorMode {
 2633        &self.mode
 2634    }
 2635
 2636    pub fn set_mode(&mut self, mode: EditorMode) {
 2637        self.mode = mode;
 2638    }
 2639
 2640    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2641        self.collaboration_hub.as_deref()
 2642    }
 2643
 2644    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2645        self.collaboration_hub = Some(hub);
 2646    }
 2647
 2648    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2649        self.in_project_search = in_project_search;
 2650    }
 2651
 2652    pub fn set_custom_context_menu(
 2653        &mut self,
 2654        f: impl 'static
 2655        + Fn(
 2656            &mut Self,
 2657            DisplayPoint,
 2658            &mut Window,
 2659            &mut Context<Self>,
 2660        ) -> Option<Entity<ui::ContextMenu>>,
 2661    ) {
 2662        self.custom_context_menu = Some(Box::new(f))
 2663    }
 2664
 2665    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2666        self.completion_provider = provider;
 2667    }
 2668
 2669    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2670        self.semantics_provider.clone()
 2671    }
 2672
 2673    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2674        self.semantics_provider = provider;
 2675    }
 2676
 2677    pub fn set_edit_prediction_provider<T>(
 2678        &mut self,
 2679        provider: Option<Entity<T>>,
 2680        window: &mut Window,
 2681        cx: &mut Context<Self>,
 2682    ) where
 2683        T: EditPredictionProvider,
 2684    {
 2685        self.edit_prediction_provider =
 2686            provider.map(|provider| RegisteredInlineCompletionProvider {
 2687                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2688                    if this.focus_handle.is_focused(window) {
 2689                        this.update_visible_inline_completion(window, cx);
 2690                    }
 2691                }),
 2692                provider: Arc::new(provider),
 2693            });
 2694        self.update_edit_prediction_settings(cx);
 2695        self.refresh_inline_completion(false, false, window, cx);
 2696    }
 2697
 2698    pub fn placeholder_text(&self) -> Option<&str> {
 2699        self.placeholder_text.as_deref()
 2700    }
 2701
 2702    pub fn set_placeholder_text(
 2703        &mut self,
 2704        placeholder_text: impl Into<Arc<str>>,
 2705        cx: &mut Context<Self>,
 2706    ) {
 2707        let placeholder_text = Some(placeholder_text.into());
 2708        if self.placeholder_text != placeholder_text {
 2709            self.placeholder_text = placeholder_text;
 2710            cx.notify();
 2711        }
 2712    }
 2713
 2714    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2715        self.cursor_shape = cursor_shape;
 2716
 2717        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2718        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2719
 2720        cx.notify();
 2721    }
 2722
 2723    pub fn set_current_line_highlight(
 2724        &mut self,
 2725        current_line_highlight: Option<CurrentLineHighlight>,
 2726    ) {
 2727        self.current_line_highlight = current_line_highlight;
 2728    }
 2729
 2730    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2731        self.collapse_matches = collapse_matches;
 2732    }
 2733
 2734    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2735        let buffers = self.buffer.read(cx).all_buffers();
 2736        let Some(project) = self.project.as_ref() else {
 2737            return;
 2738        };
 2739        project.update(cx, |project, cx| {
 2740            for buffer in buffers {
 2741                self.registered_buffers
 2742                    .entry(buffer.read(cx).remote_id())
 2743                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2744            }
 2745        })
 2746    }
 2747
 2748    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2749        if self.collapse_matches {
 2750            return range.start..range.start;
 2751        }
 2752        range.clone()
 2753    }
 2754
 2755    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2756        if self.display_map.read(cx).clip_at_line_ends != clip {
 2757            self.display_map
 2758                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2759        }
 2760    }
 2761
 2762    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2763        self.input_enabled = input_enabled;
 2764    }
 2765
 2766    pub fn set_inline_completions_hidden_for_vim_mode(
 2767        &mut self,
 2768        hidden: bool,
 2769        window: &mut Window,
 2770        cx: &mut Context<Self>,
 2771    ) {
 2772        if hidden != self.inline_completions_hidden_for_vim_mode {
 2773            self.inline_completions_hidden_for_vim_mode = hidden;
 2774            if hidden {
 2775                self.update_visible_inline_completion(window, cx);
 2776            } else {
 2777                self.refresh_inline_completion(true, false, window, cx);
 2778            }
 2779        }
 2780    }
 2781
 2782    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2783        self.menu_inline_completions_policy = value;
 2784    }
 2785
 2786    pub fn set_autoindent(&mut self, autoindent: bool) {
 2787        if autoindent {
 2788            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2789        } else {
 2790            self.autoindent_mode = None;
 2791        }
 2792    }
 2793
 2794    pub fn read_only(&self, cx: &App) -> bool {
 2795        self.read_only || self.buffer.read(cx).read_only()
 2796    }
 2797
 2798    pub fn set_read_only(&mut self, read_only: bool) {
 2799        self.read_only = read_only;
 2800    }
 2801
 2802    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2803        self.use_autoclose = autoclose;
 2804    }
 2805
 2806    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2807        self.use_auto_surround = auto_surround;
 2808    }
 2809
 2810    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2811        self.auto_replace_emoji_shortcode = auto_replace;
 2812    }
 2813
 2814    pub fn toggle_edit_predictions(
 2815        &mut self,
 2816        _: &ToggleEditPrediction,
 2817        window: &mut Window,
 2818        cx: &mut Context<Self>,
 2819    ) {
 2820        if self.show_inline_completions_override.is_some() {
 2821            self.set_show_edit_predictions(None, window, cx);
 2822        } else {
 2823            let show_edit_predictions = !self.edit_predictions_enabled();
 2824            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2825        }
 2826    }
 2827
 2828    pub fn set_show_edit_predictions(
 2829        &mut self,
 2830        show_edit_predictions: Option<bool>,
 2831        window: &mut Window,
 2832        cx: &mut Context<Self>,
 2833    ) {
 2834        self.show_inline_completions_override = show_edit_predictions;
 2835        self.update_edit_prediction_settings(cx);
 2836
 2837        if let Some(false) = show_edit_predictions {
 2838            self.discard_inline_completion(false, cx);
 2839        } else {
 2840            self.refresh_inline_completion(false, true, window, cx);
 2841        }
 2842    }
 2843
 2844    fn inline_completions_disabled_in_scope(
 2845        &self,
 2846        buffer: &Entity<Buffer>,
 2847        buffer_position: language::Anchor,
 2848        cx: &App,
 2849    ) -> bool {
 2850        let snapshot = buffer.read(cx).snapshot();
 2851        let settings = snapshot.settings_at(buffer_position, cx);
 2852
 2853        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2854            return false;
 2855        };
 2856
 2857        scope.override_name().map_or(false, |scope_name| {
 2858            settings
 2859                .edit_predictions_disabled_in
 2860                .iter()
 2861                .any(|s| s == scope_name)
 2862        })
 2863    }
 2864
 2865    pub fn set_use_modal_editing(&mut self, to: bool) {
 2866        self.use_modal_editing = to;
 2867    }
 2868
 2869    pub fn use_modal_editing(&self) -> bool {
 2870        self.use_modal_editing
 2871    }
 2872
 2873    fn selections_did_change(
 2874        &mut self,
 2875        local: bool,
 2876        old_cursor_position: &Anchor,
 2877        effects: SelectionEffects,
 2878        window: &mut Window,
 2879        cx: &mut Context<Self>,
 2880    ) {
 2881        window.invalidate_character_coordinates();
 2882
 2883        // Copy selections to primary selection buffer
 2884        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2885        if local {
 2886            let selections = self.selections.all::<usize>(cx);
 2887            let buffer_handle = self.buffer.read(cx).read(cx);
 2888
 2889            let mut text = String::new();
 2890            for (index, selection) in selections.iter().enumerate() {
 2891                let text_for_selection = buffer_handle
 2892                    .text_for_range(selection.start..selection.end)
 2893                    .collect::<String>();
 2894
 2895                text.push_str(&text_for_selection);
 2896                if index != selections.len() - 1 {
 2897                    text.push('\n');
 2898                }
 2899            }
 2900
 2901            if !text.is_empty() {
 2902                cx.write_to_primary(ClipboardItem::new_string(text));
 2903            }
 2904        }
 2905
 2906        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2907            self.buffer.update(cx, |buffer, cx| {
 2908                buffer.set_active_selections(
 2909                    &self.selections.disjoint_anchors(),
 2910                    self.selections.line_mode,
 2911                    self.cursor_shape,
 2912                    cx,
 2913                )
 2914            });
 2915        }
 2916        let display_map = self
 2917            .display_map
 2918            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2919        let buffer = &display_map.buffer_snapshot;
 2920        if self.selections.count() == 1 {
 2921            self.add_selections_state = None;
 2922        }
 2923        self.select_next_state = None;
 2924        self.select_prev_state = None;
 2925        self.select_syntax_node_history.try_clear();
 2926        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2927        self.snippet_stack
 2928            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2929        self.take_rename(false, window, cx);
 2930
 2931        let newest_selection = self.selections.newest_anchor();
 2932        let new_cursor_position = newest_selection.head();
 2933        let selection_start = newest_selection.start;
 2934
 2935        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2936            self.push_to_nav_history(
 2937                *old_cursor_position,
 2938                Some(new_cursor_position.to_point(buffer)),
 2939                false,
 2940                effects.nav_history == Some(true),
 2941                cx,
 2942            );
 2943        }
 2944
 2945        if local {
 2946            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2947                if !self.registered_buffers.contains_key(&buffer_id) {
 2948                    if let Some(project) = self.project.as_ref() {
 2949                        project.update(cx, |project, cx| {
 2950                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2951                                return;
 2952                            };
 2953                            self.registered_buffers.insert(
 2954                                buffer_id,
 2955                                project.register_buffer_with_language_servers(&buffer, cx),
 2956                            );
 2957                        })
 2958                    }
 2959                }
 2960            }
 2961
 2962            let mut context_menu = self.context_menu.borrow_mut();
 2963            let completion_menu = match context_menu.as_ref() {
 2964                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2965                Some(CodeContextMenu::CodeActions(_)) => {
 2966                    *context_menu = None;
 2967                    None
 2968                }
 2969                None => None,
 2970            };
 2971            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2972            drop(context_menu);
 2973
 2974            if effects.completions {
 2975                if let Some(completion_position) = completion_position {
 2976                    let start_offset = selection_start.to_offset(buffer);
 2977                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2978                    let continue_showing = if position_matches {
 2979                        if self.snippet_stack.is_empty() {
 2980                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2981                        } else {
 2982                            // Snippet choices can be shown even when the cursor is in whitespace.
 2983                            // Dismissing the menu with actions like backspace is handled by
 2984                            // invalidation regions.
 2985                            true
 2986                        }
 2987                    } else {
 2988                        false
 2989                    };
 2990
 2991                    if continue_showing {
 2992                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2993                    } else {
 2994                        self.hide_context_menu(window, cx);
 2995                    }
 2996                }
 2997            }
 2998
 2999            hide_hover(self, cx);
 3000
 3001            if old_cursor_position.to_display_point(&display_map).row()
 3002                != new_cursor_position.to_display_point(&display_map).row()
 3003            {
 3004                self.available_code_actions.take();
 3005            }
 3006            self.refresh_code_actions(window, cx);
 3007            self.refresh_document_highlights(cx);
 3008            self.refresh_selected_text_highlights(false, window, cx);
 3009            refresh_matching_bracket_highlights(self, window, cx);
 3010            self.update_visible_inline_completion(window, cx);
 3011            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3012            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3013            self.inline_blame_popover.take();
 3014            if self.git_blame_inline_enabled {
 3015                self.start_inline_blame_timer(window, cx);
 3016            }
 3017        }
 3018
 3019        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3020        cx.emit(EditorEvent::SelectionsChanged { local });
 3021
 3022        let selections = &self.selections.disjoint;
 3023        if selections.len() == 1 {
 3024            cx.emit(SearchEvent::ActiveMatchChanged)
 3025        }
 3026        if local {
 3027            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3028                let inmemory_selections = selections
 3029                    .iter()
 3030                    .map(|s| {
 3031                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3032                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3033                    })
 3034                    .collect();
 3035                self.update_restoration_data(cx, |data| {
 3036                    data.selections = inmemory_selections;
 3037                });
 3038
 3039                if WorkspaceSettings::get(None, cx).restore_on_startup
 3040                    != RestoreOnStartupBehavior::None
 3041                {
 3042                    if let Some(workspace_id) =
 3043                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3044                    {
 3045                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3046                        let selections = selections.clone();
 3047                        let background_executor = cx.background_executor().clone();
 3048                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3049                        self.serialize_selections = cx.background_spawn(async move {
 3050                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3051                            let db_selections = selections
 3052                                .iter()
 3053                                .map(|selection| {
 3054                                    (
 3055                                        selection.start.to_offset(&snapshot),
 3056                                        selection.end.to_offset(&snapshot),
 3057                                    )
 3058                                })
 3059                                .collect();
 3060
 3061                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3062                                .await
 3063                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3064                                .log_err();
 3065                        });
 3066                    }
 3067                }
 3068            }
 3069        }
 3070
 3071        cx.notify();
 3072    }
 3073
 3074    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3075        use text::ToOffset as _;
 3076        use text::ToPoint as _;
 3077
 3078        if self.mode.is_minimap()
 3079            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3080        {
 3081            return;
 3082        }
 3083
 3084        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3085            return;
 3086        };
 3087
 3088        let snapshot = singleton.read(cx).snapshot();
 3089        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3090            let display_snapshot = display_map.snapshot(cx);
 3091
 3092            display_snapshot
 3093                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3094                .map(|fold| {
 3095                    fold.range.start.text_anchor.to_point(&snapshot)
 3096                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3097                })
 3098                .collect()
 3099        });
 3100        self.update_restoration_data(cx, |data| {
 3101            data.folds = inmemory_folds;
 3102        });
 3103
 3104        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3105            return;
 3106        };
 3107        let background_executor = cx.background_executor().clone();
 3108        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3109        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3110            display_map
 3111                .snapshot(cx)
 3112                .folds_in_range(0..snapshot.len())
 3113                .map(|fold| {
 3114                    (
 3115                        fold.range.start.text_anchor.to_offset(&snapshot),
 3116                        fold.range.end.text_anchor.to_offset(&snapshot),
 3117                    )
 3118                })
 3119                .collect()
 3120        });
 3121        self.serialize_folds = cx.background_spawn(async move {
 3122            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3123            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3124                .await
 3125                .with_context(|| {
 3126                    format!(
 3127                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3128                    )
 3129                })
 3130                .log_err();
 3131        });
 3132    }
 3133
 3134    pub fn sync_selections(
 3135        &mut self,
 3136        other: Entity<Editor>,
 3137        cx: &mut Context<Self>,
 3138    ) -> gpui::Subscription {
 3139        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3140        self.selections.change_with(cx, |selections| {
 3141            selections.select_anchors(other_selections);
 3142        });
 3143
 3144        let other_subscription =
 3145            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3146                EditorEvent::SelectionsChanged { local: true } => {
 3147                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3148                    if other_selections.is_empty() {
 3149                        return;
 3150                    }
 3151                    this.selections.change_with(cx, |selections| {
 3152                        selections.select_anchors(other_selections);
 3153                    });
 3154                }
 3155                _ => {}
 3156            });
 3157
 3158        let this_subscription =
 3159            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3160                EditorEvent::SelectionsChanged { local: true } => {
 3161                    let these_selections = this.selections.disjoint.to_vec();
 3162                    if these_selections.is_empty() {
 3163                        return;
 3164                    }
 3165                    other.update(cx, |other_editor, cx| {
 3166                        other_editor.selections.change_with(cx, |selections| {
 3167                            selections.select_anchors(these_selections);
 3168                        })
 3169                    });
 3170                }
 3171                _ => {}
 3172            });
 3173
 3174        Subscription::join(other_subscription, this_subscription)
 3175    }
 3176
 3177    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3178    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3179    /// effects of selection change occur at the end of the transaction.
 3180    pub fn change_selections<R>(
 3181        &mut self,
 3182        effects: SelectionEffects,
 3183        window: &mut Window,
 3184        cx: &mut Context<Self>,
 3185        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3186    ) -> R {
 3187        if let Some(state) = &mut self.deferred_selection_effects_state {
 3188            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3189            state.effects.completions = effects.completions;
 3190            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3191            let (changed, result) = self.selections.change_with(cx, change);
 3192            state.changed |= changed;
 3193            return result;
 3194        }
 3195        let mut state = DeferredSelectionEffectsState {
 3196            changed: false,
 3197            effects,
 3198            old_cursor_position: self.selections.newest_anchor().head(),
 3199            history_entry: SelectionHistoryEntry {
 3200                selections: self.selections.disjoint_anchors(),
 3201                select_next_state: self.select_next_state.clone(),
 3202                select_prev_state: self.select_prev_state.clone(),
 3203                add_selections_state: self.add_selections_state.clone(),
 3204            },
 3205        };
 3206        let (changed, result) = self.selections.change_with(cx, change);
 3207        state.changed = state.changed || changed;
 3208        if self.defer_selection_effects {
 3209            self.deferred_selection_effects_state = Some(state);
 3210        } else {
 3211            self.apply_selection_effects(state, window, cx);
 3212        }
 3213        result
 3214    }
 3215
 3216    /// Defers the effects of selection change, so that the effects of multiple calls to
 3217    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3218    /// to selection history and the state of popovers based on selection position aren't
 3219    /// erroneously updated.
 3220    pub fn with_selection_effects_deferred<R>(
 3221        &mut self,
 3222        window: &mut Window,
 3223        cx: &mut Context<Self>,
 3224        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3225    ) -> R {
 3226        let already_deferred = self.defer_selection_effects;
 3227        self.defer_selection_effects = true;
 3228        let result = update(self, window, cx);
 3229        if !already_deferred {
 3230            self.defer_selection_effects = false;
 3231            if let Some(state) = self.deferred_selection_effects_state.take() {
 3232                self.apply_selection_effects(state, window, cx);
 3233            }
 3234        }
 3235        result
 3236    }
 3237
 3238    fn apply_selection_effects(
 3239        &mut self,
 3240        state: DeferredSelectionEffectsState,
 3241        window: &mut Window,
 3242        cx: &mut Context<Self>,
 3243    ) {
 3244        if state.changed {
 3245            self.selection_history.push(state.history_entry);
 3246
 3247            if let Some(autoscroll) = state.effects.scroll {
 3248                self.request_autoscroll(autoscroll, cx);
 3249            }
 3250
 3251            let old_cursor_position = &state.old_cursor_position;
 3252
 3253            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3254
 3255            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3256                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3257            }
 3258        }
 3259    }
 3260
 3261    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3262    where
 3263        I: IntoIterator<Item = (Range<S>, T)>,
 3264        S: ToOffset,
 3265        T: Into<Arc<str>>,
 3266    {
 3267        if self.read_only(cx) {
 3268            return;
 3269        }
 3270
 3271        self.buffer
 3272            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3273    }
 3274
 3275    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3276    where
 3277        I: IntoIterator<Item = (Range<S>, T)>,
 3278        S: ToOffset,
 3279        T: Into<Arc<str>>,
 3280    {
 3281        if self.read_only(cx) {
 3282            return;
 3283        }
 3284
 3285        self.buffer.update(cx, |buffer, cx| {
 3286            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3287        });
 3288    }
 3289
 3290    pub fn edit_with_block_indent<I, S, T>(
 3291        &mut self,
 3292        edits: I,
 3293        original_indent_columns: Vec<Option<u32>>,
 3294        cx: &mut Context<Self>,
 3295    ) where
 3296        I: IntoIterator<Item = (Range<S>, T)>,
 3297        S: ToOffset,
 3298        T: Into<Arc<str>>,
 3299    {
 3300        if self.read_only(cx) {
 3301            return;
 3302        }
 3303
 3304        self.buffer.update(cx, |buffer, cx| {
 3305            buffer.edit(
 3306                edits,
 3307                Some(AutoindentMode::Block {
 3308                    original_indent_columns,
 3309                }),
 3310                cx,
 3311            )
 3312        });
 3313    }
 3314
 3315    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3316        self.hide_context_menu(window, cx);
 3317
 3318        match phase {
 3319            SelectPhase::Begin {
 3320                position,
 3321                add,
 3322                click_count,
 3323            } => self.begin_selection(position, add, click_count, window, cx),
 3324            SelectPhase::BeginColumnar {
 3325                position,
 3326                goal_column,
 3327                reset,
 3328                mode,
 3329            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3330            SelectPhase::Extend {
 3331                position,
 3332                click_count,
 3333            } => self.extend_selection(position, click_count, window, cx),
 3334            SelectPhase::Update {
 3335                position,
 3336                goal_column,
 3337                scroll_delta,
 3338            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3339            SelectPhase::End => self.end_selection(window, cx),
 3340        }
 3341    }
 3342
 3343    fn extend_selection(
 3344        &mut self,
 3345        position: DisplayPoint,
 3346        click_count: usize,
 3347        window: &mut Window,
 3348        cx: &mut Context<Self>,
 3349    ) {
 3350        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3351        let tail = self.selections.newest::<usize>(cx).tail();
 3352        self.begin_selection(position, false, click_count, window, cx);
 3353
 3354        let position = position.to_offset(&display_map, Bias::Left);
 3355        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3356
 3357        let mut pending_selection = self
 3358            .selections
 3359            .pending_anchor()
 3360            .expect("extend_selection not called with pending selection");
 3361        if position >= tail {
 3362            pending_selection.start = tail_anchor;
 3363        } else {
 3364            pending_selection.end = tail_anchor;
 3365            pending_selection.reversed = true;
 3366        }
 3367
 3368        let mut pending_mode = self.selections.pending_mode().unwrap();
 3369        match &mut pending_mode {
 3370            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3371            _ => {}
 3372        }
 3373
 3374        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3375            SelectionEffects::scroll(Autoscroll::fit())
 3376        } else {
 3377            SelectionEffects::no_scroll()
 3378        };
 3379
 3380        self.change_selections(effects, window, cx, |s| {
 3381            s.set_pending(pending_selection, pending_mode)
 3382        });
 3383    }
 3384
 3385    fn begin_selection(
 3386        &mut self,
 3387        position: DisplayPoint,
 3388        add: bool,
 3389        click_count: usize,
 3390        window: &mut Window,
 3391        cx: &mut Context<Self>,
 3392    ) {
 3393        if !self.focus_handle.is_focused(window) {
 3394            self.last_focused_descendant = None;
 3395            window.focus(&self.focus_handle);
 3396        }
 3397
 3398        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3399        let buffer = &display_map.buffer_snapshot;
 3400        let position = display_map.clip_point(position, Bias::Left);
 3401
 3402        let start;
 3403        let end;
 3404        let mode;
 3405        let mut auto_scroll;
 3406        match click_count {
 3407            1 => {
 3408                start = buffer.anchor_before(position.to_point(&display_map));
 3409                end = start;
 3410                mode = SelectMode::Character;
 3411                auto_scroll = true;
 3412            }
 3413            2 => {
 3414                let position = display_map
 3415                    .clip_point(position, Bias::Left)
 3416                    .to_offset(&display_map, Bias::Left);
 3417                let (range, _) = buffer.surrounding_word(position, false);
 3418                start = buffer.anchor_before(range.start);
 3419                end = buffer.anchor_before(range.end);
 3420                mode = SelectMode::Word(start..end);
 3421                auto_scroll = true;
 3422            }
 3423            3 => {
 3424                let position = display_map
 3425                    .clip_point(position, Bias::Left)
 3426                    .to_point(&display_map);
 3427                let line_start = display_map.prev_line_boundary(position).0;
 3428                let next_line_start = buffer.clip_point(
 3429                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3430                    Bias::Left,
 3431                );
 3432                start = buffer.anchor_before(line_start);
 3433                end = buffer.anchor_before(next_line_start);
 3434                mode = SelectMode::Line(start..end);
 3435                auto_scroll = true;
 3436            }
 3437            _ => {
 3438                start = buffer.anchor_before(0);
 3439                end = buffer.anchor_before(buffer.len());
 3440                mode = SelectMode::All;
 3441                auto_scroll = false;
 3442            }
 3443        }
 3444        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3445
 3446        let point_to_delete: Option<usize> = {
 3447            let selected_points: Vec<Selection<Point>> =
 3448                self.selections.disjoint_in_range(start..end, cx);
 3449
 3450            if !add || click_count > 1 {
 3451                None
 3452            } else if !selected_points.is_empty() {
 3453                Some(selected_points[0].id)
 3454            } else {
 3455                let clicked_point_already_selected =
 3456                    self.selections.disjoint.iter().find(|selection| {
 3457                        selection.start.to_point(buffer) == start.to_point(buffer)
 3458                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3459                    });
 3460
 3461                clicked_point_already_selected.map(|selection| selection.id)
 3462            }
 3463        };
 3464
 3465        let selections_count = self.selections.count();
 3466        let effects = if auto_scroll {
 3467            SelectionEffects::default()
 3468        } else {
 3469            SelectionEffects::no_scroll()
 3470        };
 3471
 3472        self.change_selections(effects, window, cx, |s| {
 3473            if let Some(point_to_delete) = point_to_delete {
 3474                s.delete(point_to_delete);
 3475
 3476                if selections_count == 1 {
 3477                    s.set_pending_anchor_range(start..end, mode);
 3478                }
 3479            } else {
 3480                if !add {
 3481                    s.clear_disjoint();
 3482                }
 3483
 3484                s.set_pending_anchor_range(start..end, mode);
 3485            }
 3486        });
 3487    }
 3488
 3489    fn begin_columnar_selection(
 3490        &mut self,
 3491        position: DisplayPoint,
 3492        goal_column: u32,
 3493        reset: bool,
 3494        mode: ColumnarMode,
 3495        window: &mut Window,
 3496        cx: &mut Context<Self>,
 3497    ) {
 3498        if !self.focus_handle.is_focused(window) {
 3499            self.last_focused_descendant = None;
 3500            window.focus(&self.focus_handle);
 3501        }
 3502
 3503        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3504
 3505        if reset {
 3506            let pointer_position = display_map
 3507                .buffer_snapshot
 3508                .anchor_before(position.to_point(&display_map));
 3509
 3510            self.change_selections(
 3511                SelectionEffects::scroll(Autoscroll::newest()),
 3512                window,
 3513                cx,
 3514                |s| {
 3515                    s.clear_disjoint();
 3516                    s.set_pending_anchor_range(
 3517                        pointer_position..pointer_position,
 3518                        SelectMode::Character,
 3519                    );
 3520                },
 3521            );
 3522        };
 3523
 3524        let tail = self.selections.newest::<Point>(cx).tail();
 3525        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3526        self.columnar_selection_state = match mode {
 3527            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3528                selection_tail: selection_anchor,
 3529                display_point: if reset {
 3530                    if position.column() != goal_column {
 3531                        Some(DisplayPoint::new(position.row(), goal_column))
 3532                    } else {
 3533                        None
 3534                    }
 3535                } else {
 3536                    None
 3537                },
 3538            }),
 3539            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3540                selection_tail: selection_anchor,
 3541            }),
 3542        };
 3543
 3544        if !reset {
 3545            self.select_columns(position, goal_column, &display_map, window, cx);
 3546        }
 3547    }
 3548
 3549    fn update_selection(
 3550        &mut self,
 3551        position: DisplayPoint,
 3552        goal_column: u32,
 3553        scroll_delta: gpui::Point<f32>,
 3554        window: &mut Window,
 3555        cx: &mut Context<Self>,
 3556    ) {
 3557        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3558
 3559        if self.columnar_selection_state.is_some() {
 3560            self.select_columns(position, goal_column, &display_map, window, cx);
 3561        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3562            let buffer = &display_map.buffer_snapshot;
 3563            let head;
 3564            let tail;
 3565            let mode = self.selections.pending_mode().unwrap();
 3566            match &mode {
 3567                SelectMode::Character => {
 3568                    head = position.to_point(&display_map);
 3569                    tail = pending.tail().to_point(buffer);
 3570                }
 3571                SelectMode::Word(original_range) => {
 3572                    let offset = display_map
 3573                        .clip_point(position, Bias::Left)
 3574                        .to_offset(&display_map, Bias::Left);
 3575                    let original_range = original_range.to_offset(buffer);
 3576
 3577                    let head_offset = if buffer.is_inside_word(offset, false)
 3578                        || original_range.contains(&offset)
 3579                    {
 3580                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3581                        if word_range.start < original_range.start {
 3582                            word_range.start
 3583                        } else {
 3584                            word_range.end
 3585                        }
 3586                    } else {
 3587                        offset
 3588                    };
 3589
 3590                    head = head_offset.to_point(buffer);
 3591                    if head_offset <= original_range.start {
 3592                        tail = original_range.end.to_point(buffer);
 3593                    } else {
 3594                        tail = original_range.start.to_point(buffer);
 3595                    }
 3596                }
 3597                SelectMode::Line(original_range) => {
 3598                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3599
 3600                    let position = display_map
 3601                        .clip_point(position, Bias::Left)
 3602                        .to_point(&display_map);
 3603                    let line_start = display_map.prev_line_boundary(position).0;
 3604                    let next_line_start = buffer.clip_point(
 3605                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3606                        Bias::Left,
 3607                    );
 3608
 3609                    if line_start < original_range.start {
 3610                        head = line_start
 3611                    } else {
 3612                        head = next_line_start
 3613                    }
 3614
 3615                    if head <= original_range.start {
 3616                        tail = original_range.end;
 3617                    } else {
 3618                        tail = original_range.start;
 3619                    }
 3620                }
 3621                SelectMode::All => {
 3622                    return;
 3623                }
 3624            };
 3625
 3626            if head < tail {
 3627                pending.start = buffer.anchor_before(head);
 3628                pending.end = buffer.anchor_before(tail);
 3629                pending.reversed = true;
 3630            } else {
 3631                pending.start = buffer.anchor_before(tail);
 3632                pending.end = buffer.anchor_before(head);
 3633                pending.reversed = false;
 3634            }
 3635
 3636            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3637                s.set_pending(pending, mode);
 3638            });
 3639        } else {
 3640            log::error!("update_selection dispatched with no pending selection");
 3641            return;
 3642        }
 3643
 3644        self.apply_scroll_delta(scroll_delta, window, cx);
 3645        cx.notify();
 3646    }
 3647
 3648    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3649        self.columnar_selection_state.take();
 3650        if self.selections.pending_anchor().is_some() {
 3651            let selections = self.selections.all::<usize>(cx);
 3652            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3653                s.select(selections);
 3654                s.clear_pending();
 3655            });
 3656        }
 3657    }
 3658
 3659    fn select_columns(
 3660        &mut self,
 3661        head: DisplayPoint,
 3662        goal_column: u32,
 3663        display_map: &DisplaySnapshot,
 3664        window: &mut Window,
 3665        cx: &mut Context<Self>,
 3666    ) {
 3667        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3668            return;
 3669        };
 3670
 3671        let tail = match columnar_state {
 3672            ColumnarSelectionState::FromMouse {
 3673                selection_tail,
 3674                display_point,
 3675            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3676            ColumnarSelectionState::FromSelection { selection_tail } => {
 3677                selection_tail.to_display_point(&display_map)
 3678            }
 3679        };
 3680
 3681        let start_row = cmp::min(tail.row(), head.row());
 3682        let end_row = cmp::max(tail.row(), head.row());
 3683        let start_column = cmp::min(tail.column(), goal_column);
 3684        let end_column = cmp::max(tail.column(), goal_column);
 3685        let reversed = start_column < tail.column();
 3686
 3687        let selection_ranges = (start_row.0..=end_row.0)
 3688            .map(DisplayRow)
 3689            .filter_map(|row| {
 3690                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3691                    || start_column <= display_map.line_len(row))
 3692                    && !display_map.is_block_line(row)
 3693                {
 3694                    let start = display_map
 3695                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3696                        .to_point(display_map);
 3697                    let end = display_map
 3698                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3699                        .to_point(display_map);
 3700                    if reversed {
 3701                        Some(end..start)
 3702                    } else {
 3703                        Some(start..end)
 3704                    }
 3705                } else {
 3706                    None
 3707                }
 3708            })
 3709            .collect::<Vec<_>>();
 3710
 3711        let ranges = match columnar_state {
 3712            ColumnarSelectionState::FromMouse { .. } => {
 3713                let mut non_empty_ranges = selection_ranges
 3714                    .iter()
 3715                    .filter(|selection_range| selection_range.start != selection_range.end)
 3716                    .peekable();
 3717                if non_empty_ranges.peek().is_some() {
 3718                    non_empty_ranges.cloned().collect()
 3719                } else {
 3720                    selection_ranges
 3721                }
 3722            }
 3723            _ => selection_ranges,
 3724        };
 3725
 3726        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3727            s.select_ranges(ranges);
 3728        });
 3729        cx.notify();
 3730    }
 3731
 3732    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3733        self.selections
 3734            .all_adjusted(cx)
 3735            .iter()
 3736            .any(|selection| !selection.is_empty())
 3737    }
 3738
 3739    pub fn has_pending_nonempty_selection(&self) -> bool {
 3740        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3741            Some(Selection { start, end, .. }) => start != end,
 3742            None => false,
 3743        };
 3744
 3745        pending_nonempty_selection
 3746            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3747    }
 3748
 3749    pub fn has_pending_selection(&self) -> bool {
 3750        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3751    }
 3752
 3753    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3754        self.selection_mark_mode = false;
 3755        self.selection_drag_state = SelectionDragState::None;
 3756
 3757        if self.clear_expanded_diff_hunks(cx) {
 3758            cx.notify();
 3759            return;
 3760        }
 3761        if self.dismiss_menus_and_popups(true, window, cx) {
 3762            return;
 3763        }
 3764
 3765        if self.mode.is_full()
 3766            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3767        {
 3768            return;
 3769        }
 3770
 3771        cx.propagate();
 3772    }
 3773
 3774    pub fn dismiss_menus_and_popups(
 3775        &mut self,
 3776        is_user_requested: bool,
 3777        window: &mut Window,
 3778        cx: &mut Context<Self>,
 3779    ) -> bool {
 3780        if self.take_rename(false, window, cx).is_some() {
 3781            return true;
 3782        }
 3783
 3784        if hide_hover(self, cx) {
 3785            return true;
 3786        }
 3787
 3788        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3789            return true;
 3790        }
 3791
 3792        if self.hide_context_menu(window, cx).is_some() {
 3793            return true;
 3794        }
 3795
 3796        if self.mouse_context_menu.take().is_some() {
 3797            return true;
 3798        }
 3799
 3800        if is_user_requested && self.discard_inline_completion(true, cx) {
 3801            return true;
 3802        }
 3803
 3804        if self.snippet_stack.pop().is_some() {
 3805            return true;
 3806        }
 3807
 3808        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3809            self.dismiss_diagnostics(cx);
 3810            return true;
 3811        }
 3812
 3813        false
 3814    }
 3815
 3816    fn linked_editing_ranges_for(
 3817        &self,
 3818        selection: Range<text::Anchor>,
 3819        cx: &App,
 3820    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3821        if self.linked_edit_ranges.is_empty() {
 3822            return None;
 3823        }
 3824        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3825            selection.end.buffer_id.and_then(|end_buffer_id| {
 3826                if selection.start.buffer_id != Some(end_buffer_id) {
 3827                    return None;
 3828                }
 3829                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3830                let snapshot = buffer.read(cx).snapshot();
 3831                self.linked_edit_ranges
 3832                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3833                    .map(|ranges| (ranges, snapshot, buffer))
 3834            })?;
 3835        use text::ToOffset as TO;
 3836        // find offset from the start of current range to current cursor position
 3837        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3838
 3839        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3840        let start_difference = start_offset - start_byte_offset;
 3841        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3842        let end_difference = end_offset - start_byte_offset;
 3843        // Current range has associated linked ranges.
 3844        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3845        for range in linked_ranges.iter() {
 3846            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3847            let end_offset = start_offset + end_difference;
 3848            let start_offset = start_offset + start_difference;
 3849            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3850                continue;
 3851            }
 3852            if self.selections.disjoint_anchor_ranges().any(|s| {
 3853                if s.start.buffer_id != selection.start.buffer_id
 3854                    || s.end.buffer_id != selection.end.buffer_id
 3855                {
 3856                    return false;
 3857                }
 3858                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3859                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3860            }) {
 3861                continue;
 3862            }
 3863            let start = buffer_snapshot.anchor_after(start_offset);
 3864            let end = buffer_snapshot.anchor_after(end_offset);
 3865            linked_edits
 3866                .entry(buffer.clone())
 3867                .or_default()
 3868                .push(start..end);
 3869        }
 3870        Some(linked_edits)
 3871    }
 3872
 3873    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3874        let text: Arc<str> = text.into();
 3875
 3876        if self.read_only(cx) {
 3877            return;
 3878        }
 3879
 3880        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3881
 3882        let selections = self.selections.all_adjusted(cx);
 3883        let mut bracket_inserted = false;
 3884        let mut edits = Vec::new();
 3885        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3886        let mut new_selections = Vec::with_capacity(selections.len());
 3887        let mut new_autoclose_regions = Vec::new();
 3888        let snapshot = self.buffer.read(cx).read(cx);
 3889        let mut clear_linked_edit_ranges = false;
 3890
 3891        for (selection, autoclose_region) in
 3892            self.selections_with_autoclose_regions(selections, &snapshot)
 3893        {
 3894            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3895                // Determine if the inserted text matches the opening or closing
 3896                // bracket of any of this language's bracket pairs.
 3897                let mut bracket_pair = None;
 3898                let mut is_bracket_pair_start = false;
 3899                let mut is_bracket_pair_end = false;
 3900                if !text.is_empty() {
 3901                    let mut bracket_pair_matching_end = None;
 3902                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3903                    //  and they are removing the character that triggered IME popup.
 3904                    for (pair, enabled) in scope.brackets() {
 3905                        if !pair.close && !pair.surround {
 3906                            continue;
 3907                        }
 3908
 3909                        if enabled && pair.start.ends_with(text.as_ref()) {
 3910                            let prefix_len = pair.start.len() - text.len();
 3911                            let preceding_text_matches_prefix = prefix_len == 0
 3912                                || (selection.start.column >= (prefix_len as u32)
 3913                                    && snapshot.contains_str_at(
 3914                                        Point::new(
 3915                                            selection.start.row,
 3916                                            selection.start.column - (prefix_len as u32),
 3917                                        ),
 3918                                        &pair.start[..prefix_len],
 3919                                    ));
 3920                            if preceding_text_matches_prefix {
 3921                                bracket_pair = Some(pair.clone());
 3922                                is_bracket_pair_start = true;
 3923                                break;
 3924                            }
 3925                        }
 3926                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3927                        {
 3928                            // take first bracket pair matching end, but don't break in case a later bracket
 3929                            // pair matches start
 3930                            bracket_pair_matching_end = Some(pair.clone());
 3931                        }
 3932                    }
 3933                    if let Some(end) = bracket_pair_matching_end
 3934                        && bracket_pair.is_none()
 3935                    {
 3936                        bracket_pair = Some(end);
 3937                        is_bracket_pair_end = true;
 3938                    }
 3939                }
 3940
 3941                if let Some(bracket_pair) = bracket_pair {
 3942                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3943                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3944                    let auto_surround =
 3945                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3946                    if selection.is_empty() {
 3947                        if is_bracket_pair_start {
 3948                            // If the inserted text is a suffix of an opening bracket and the
 3949                            // selection is preceded by the rest of the opening bracket, then
 3950                            // insert the closing bracket.
 3951                            let following_text_allows_autoclose = snapshot
 3952                                .chars_at(selection.start)
 3953                                .next()
 3954                                .map_or(true, |c| scope.should_autoclose_before(c));
 3955
 3956                            let preceding_text_allows_autoclose = selection.start.column == 0
 3957                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3958                                    true,
 3959                                    |c| {
 3960                                        bracket_pair.start != bracket_pair.end
 3961                                            || !snapshot
 3962                                                .char_classifier_at(selection.start)
 3963                                                .is_word(c)
 3964                                    },
 3965                                );
 3966
 3967                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3968                                && bracket_pair.start.len() == 1
 3969                            {
 3970                                let target = bracket_pair.start.chars().next().unwrap();
 3971                                let current_line_count = snapshot
 3972                                    .reversed_chars_at(selection.start)
 3973                                    .take_while(|&c| c != '\n')
 3974                                    .filter(|&c| c == target)
 3975                                    .count();
 3976                                current_line_count % 2 == 1
 3977                            } else {
 3978                                false
 3979                            };
 3980
 3981                            if autoclose
 3982                                && bracket_pair.close
 3983                                && following_text_allows_autoclose
 3984                                && preceding_text_allows_autoclose
 3985                                && !is_closing_quote
 3986                            {
 3987                                let anchor = snapshot.anchor_before(selection.end);
 3988                                new_selections.push((selection.map(|_| anchor), text.len()));
 3989                                new_autoclose_regions.push((
 3990                                    anchor,
 3991                                    text.len(),
 3992                                    selection.id,
 3993                                    bracket_pair.clone(),
 3994                                ));
 3995                                edits.push((
 3996                                    selection.range(),
 3997                                    format!("{}{}", text, bracket_pair.end).into(),
 3998                                ));
 3999                                bracket_inserted = true;
 4000                                continue;
 4001                            }
 4002                        }
 4003
 4004                        if let Some(region) = autoclose_region {
 4005                            // If the selection is followed by an auto-inserted closing bracket,
 4006                            // then don't insert that closing bracket again; just move the selection
 4007                            // past the closing bracket.
 4008                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4009                                && text.as_ref() == region.pair.end.as_str();
 4010                            if should_skip {
 4011                                let anchor = snapshot.anchor_after(selection.end);
 4012                                new_selections
 4013                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4014                                continue;
 4015                            }
 4016                        }
 4017
 4018                        let always_treat_brackets_as_autoclosed = snapshot
 4019                            .language_settings_at(selection.start, cx)
 4020                            .always_treat_brackets_as_autoclosed;
 4021                        if always_treat_brackets_as_autoclosed
 4022                            && is_bracket_pair_end
 4023                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4024                        {
 4025                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4026                            // and the inserted text is a closing bracket and the selection is followed
 4027                            // by the closing bracket then move the selection past the closing bracket.
 4028                            let anchor = snapshot.anchor_after(selection.end);
 4029                            new_selections.push((selection.map(|_| anchor), text.len()));
 4030                            continue;
 4031                        }
 4032                    }
 4033                    // If an opening bracket is 1 character long and is typed while
 4034                    // text is selected, then surround that text with the bracket pair.
 4035                    else if auto_surround
 4036                        && bracket_pair.surround
 4037                        && is_bracket_pair_start
 4038                        && bracket_pair.start.chars().count() == 1
 4039                    {
 4040                        edits.push((selection.start..selection.start, text.clone()));
 4041                        edits.push((
 4042                            selection.end..selection.end,
 4043                            bracket_pair.end.as_str().into(),
 4044                        ));
 4045                        bracket_inserted = true;
 4046                        new_selections.push((
 4047                            Selection {
 4048                                id: selection.id,
 4049                                start: snapshot.anchor_after(selection.start),
 4050                                end: snapshot.anchor_before(selection.end),
 4051                                reversed: selection.reversed,
 4052                                goal: selection.goal,
 4053                            },
 4054                            0,
 4055                        ));
 4056                        continue;
 4057                    }
 4058                }
 4059            }
 4060
 4061            if self.auto_replace_emoji_shortcode
 4062                && selection.is_empty()
 4063                && text.as_ref().ends_with(':')
 4064            {
 4065                if let Some(possible_emoji_short_code) =
 4066                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4067                {
 4068                    if !possible_emoji_short_code.is_empty() {
 4069                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4070                            let emoji_shortcode_start = Point::new(
 4071                                selection.start.row,
 4072                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4073                            );
 4074
 4075                            // Remove shortcode from buffer
 4076                            edits.push((
 4077                                emoji_shortcode_start..selection.start,
 4078                                "".to_string().into(),
 4079                            ));
 4080                            new_selections.push((
 4081                                Selection {
 4082                                    id: selection.id,
 4083                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4084                                    end: snapshot.anchor_before(selection.start),
 4085                                    reversed: selection.reversed,
 4086                                    goal: selection.goal,
 4087                                },
 4088                                0,
 4089                            ));
 4090
 4091                            // Insert emoji
 4092                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4093                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4094                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4095
 4096                            continue;
 4097                        }
 4098                    }
 4099                }
 4100            }
 4101
 4102            // If not handling any auto-close operation, then just replace the selected
 4103            // text with the given input and move the selection to the end of the
 4104            // newly inserted text.
 4105            let anchor = snapshot.anchor_after(selection.end);
 4106            if !self.linked_edit_ranges.is_empty() {
 4107                let start_anchor = snapshot.anchor_before(selection.start);
 4108
 4109                let is_word_char = text.chars().next().map_or(true, |char| {
 4110                    let classifier = snapshot
 4111                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4112                        .ignore_punctuation(true);
 4113                    classifier.is_word(char)
 4114                });
 4115
 4116                if is_word_char {
 4117                    if let Some(ranges) = self
 4118                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4119                    {
 4120                        for (buffer, edits) in ranges {
 4121                            linked_edits
 4122                                .entry(buffer.clone())
 4123                                .or_default()
 4124                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4125                        }
 4126                    }
 4127                } else {
 4128                    clear_linked_edit_ranges = true;
 4129                }
 4130            }
 4131
 4132            new_selections.push((selection.map(|_| anchor), 0));
 4133            edits.push((selection.start..selection.end, text.clone()));
 4134        }
 4135
 4136        drop(snapshot);
 4137
 4138        self.transact(window, cx, |this, window, cx| {
 4139            if clear_linked_edit_ranges {
 4140                this.linked_edit_ranges.clear();
 4141            }
 4142            let initial_buffer_versions =
 4143                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4144
 4145            this.buffer.update(cx, |buffer, cx| {
 4146                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4147            });
 4148            for (buffer, edits) in linked_edits {
 4149                buffer.update(cx, |buffer, cx| {
 4150                    let snapshot = buffer.snapshot();
 4151                    let edits = edits
 4152                        .into_iter()
 4153                        .map(|(range, text)| {
 4154                            use text::ToPoint as TP;
 4155                            let end_point = TP::to_point(&range.end, &snapshot);
 4156                            let start_point = TP::to_point(&range.start, &snapshot);
 4157                            (start_point..end_point, text)
 4158                        })
 4159                        .sorted_by_key(|(range, _)| range.start);
 4160                    buffer.edit(edits, None, cx);
 4161                })
 4162            }
 4163            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4164            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4165            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4166            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4167                .zip(new_selection_deltas)
 4168                .map(|(selection, delta)| Selection {
 4169                    id: selection.id,
 4170                    start: selection.start + delta,
 4171                    end: selection.end + delta,
 4172                    reversed: selection.reversed,
 4173                    goal: SelectionGoal::None,
 4174                })
 4175                .collect::<Vec<_>>();
 4176
 4177            let mut i = 0;
 4178            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4179                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4180                let start = map.buffer_snapshot.anchor_before(position);
 4181                let end = map.buffer_snapshot.anchor_after(position);
 4182                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4183                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4184                        Ordering::Less => i += 1,
 4185                        Ordering::Greater => break,
 4186                        Ordering::Equal => {
 4187                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4188                                Ordering::Less => i += 1,
 4189                                Ordering::Equal => break,
 4190                                Ordering::Greater => break,
 4191                            }
 4192                        }
 4193                    }
 4194                }
 4195                this.autoclose_regions.insert(
 4196                    i,
 4197                    AutocloseRegion {
 4198                        selection_id,
 4199                        range: start..end,
 4200                        pair,
 4201                    },
 4202                );
 4203            }
 4204
 4205            let had_active_inline_completion = this.has_active_inline_completion();
 4206            this.change_selections(
 4207                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4208                window,
 4209                cx,
 4210                |s| s.select(new_selections),
 4211            );
 4212
 4213            if !bracket_inserted {
 4214                if let Some(on_type_format_task) =
 4215                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4216                {
 4217                    on_type_format_task.detach_and_log_err(cx);
 4218                }
 4219            }
 4220
 4221            let editor_settings = EditorSettings::get_global(cx);
 4222            if bracket_inserted
 4223                && (editor_settings.auto_signature_help
 4224                    || editor_settings.show_signature_help_after_edits)
 4225            {
 4226                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4227            }
 4228
 4229            let trigger_in_words =
 4230                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4231            if this.hard_wrap.is_some() {
 4232                let latest: Range<Point> = this.selections.newest(cx).range();
 4233                if latest.is_empty()
 4234                    && this
 4235                        .buffer()
 4236                        .read(cx)
 4237                        .snapshot(cx)
 4238                        .line_len(MultiBufferRow(latest.start.row))
 4239                        == latest.start.column
 4240                {
 4241                    this.rewrap_impl(
 4242                        RewrapOptions {
 4243                            override_language_settings: true,
 4244                            preserve_existing_whitespace: true,
 4245                        },
 4246                        cx,
 4247                    )
 4248                }
 4249            }
 4250            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4251            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4252            this.refresh_inline_completion(true, false, window, cx);
 4253            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4254        });
 4255    }
 4256
 4257    fn find_possible_emoji_shortcode_at_position(
 4258        snapshot: &MultiBufferSnapshot,
 4259        position: Point,
 4260    ) -> Option<String> {
 4261        let mut chars = Vec::new();
 4262        let mut found_colon = false;
 4263        for char in snapshot.reversed_chars_at(position).take(100) {
 4264            // Found a possible emoji shortcode in the middle of the buffer
 4265            if found_colon {
 4266                if char.is_whitespace() {
 4267                    chars.reverse();
 4268                    return Some(chars.iter().collect());
 4269                }
 4270                // If the previous character is not a whitespace, we are in the middle of a word
 4271                // and we only want to complete the shortcode if the word is made up of other emojis
 4272                let mut containing_word = String::new();
 4273                for ch in snapshot
 4274                    .reversed_chars_at(position)
 4275                    .skip(chars.len() + 1)
 4276                    .take(100)
 4277                {
 4278                    if ch.is_whitespace() {
 4279                        break;
 4280                    }
 4281                    containing_word.push(ch);
 4282                }
 4283                let containing_word = containing_word.chars().rev().collect::<String>();
 4284                if util::word_consists_of_emojis(containing_word.as_str()) {
 4285                    chars.reverse();
 4286                    return Some(chars.iter().collect());
 4287                }
 4288            }
 4289
 4290            if char.is_whitespace() || !char.is_ascii() {
 4291                return None;
 4292            }
 4293            if char == ':' {
 4294                found_colon = true;
 4295            } else {
 4296                chars.push(char);
 4297            }
 4298        }
 4299        // Found a possible emoji shortcode at the beginning of the buffer
 4300        chars.reverse();
 4301        Some(chars.iter().collect())
 4302    }
 4303
 4304    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4306        self.transact(window, cx, |this, window, cx| {
 4307            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4308                let selections = this.selections.all::<usize>(cx);
 4309                let multi_buffer = this.buffer.read(cx);
 4310                let buffer = multi_buffer.snapshot(cx);
 4311                selections
 4312                    .iter()
 4313                    .map(|selection| {
 4314                        let start_point = selection.start.to_point(&buffer);
 4315                        let mut existing_indent =
 4316                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4317                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4318                        let start = selection.start;
 4319                        let end = selection.end;
 4320                        let selection_is_empty = start == end;
 4321                        let language_scope = buffer.language_scope_at(start);
 4322                        let (
 4323                            comment_delimiter,
 4324                            doc_delimiter,
 4325                            insert_extra_newline,
 4326                            indent_on_newline,
 4327                            indent_on_extra_newline,
 4328                        ) = if let Some(language) = &language_scope {
 4329                            let mut insert_extra_newline =
 4330                                insert_extra_newline_brackets(&buffer, start..end, language)
 4331                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4332
 4333                            // Comment extension on newline is allowed only for cursor selections
 4334                            let comment_delimiter = maybe!({
 4335                                if !selection_is_empty {
 4336                                    return None;
 4337                                }
 4338
 4339                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4340                                    return None;
 4341                                }
 4342
 4343                                let delimiters = language.line_comment_prefixes();
 4344                                let max_len_of_delimiter =
 4345                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4346                                let (snapshot, range) =
 4347                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4348
 4349                                let num_of_whitespaces = snapshot
 4350                                    .chars_for_range(range.clone())
 4351                                    .take_while(|c| c.is_whitespace())
 4352                                    .count();
 4353                                let comment_candidate = snapshot
 4354                                    .chars_for_range(range)
 4355                                    .skip(num_of_whitespaces)
 4356                                    .take(max_len_of_delimiter)
 4357                                    .collect::<String>();
 4358                                let (delimiter, trimmed_len) = delimiters
 4359                                    .iter()
 4360                                    .filter_map(|delimiter| {
 4361                                        let prefix = delimiter.trim_end();
 4362                                        if comment_candidate.starts_with(prefix) {
 4363                                            Some((delimiter, prefix.len()))
 4364                                        } else {
 4365                                            None
 4366                                        }
 4367                                    })
 4368                                    .max_by_key(|(_, len)| *len)?;
 4369
 4370                                let cursor_is_placed_after_comment_marker =
 4371                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4372                                if cursor_is_placed_after_comment_marker {
 4373                                    Some(delimiter.clone())
 4374                                } else {
 4375                                    None
 4376                                }
 4377                            });
 4378
 4379                            let mut indent_on_newline = IndentSize::spaces(0);
 4380                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4381
 4382                            let doc_delimiter = maybe!({
 4383                                if !selection_is_empty {
 4384                                    return None;
 4385                                }
 4386
 4387                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4388                                    return None;
 4389                                }
 4390
 4391                                let DocumentationConfig {
 4392                                    start: start_tag,
 4393                                    end: end_tag,
 4394                                    prefix: delimiter,
 4395                                    tab_size: len,
 4396                                } = language.documentation()?;
 4397
 4398                                let is_within_block_comment = buffer
 4399                                    .language_scope_at(start_point)
 4400                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4401                                if !is_within_block_comment {
 4402                                    return None;
 4403                                }
 4404
 4405                                let (snapshot, range) =
 4406                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4407
 4408                                let num_of_whitespaces = snapshot
 4409                                    .chars_for_range(range.clone())
 4410                                    .take_while(|c| c.is_whitespace())
 4411                                    .count();
 4412
 4413                                // 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.
 4414                                let column = start_point.column;
 4415                                let cursor_is_after_start_tag = {
 4416                                    let start_tag_len = start_tag.len();
 4417                                    let start_tag_line = snapshot
 4418                                        .chars_for_range(range.clone())
 4419                                        .skip(num_of_whitespaces)
 4420                                        .take(start_tag_len)
 4421                                        .collect::<String>();
 4422                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4423                                        num_of_whitespaces + start_tag_len <= column as usize
 4424                                    } else {
 4425                                        false
 4426                                    }
 4427                                };
 4428
 4429                                let cursor_is_after_delimiter = {
 4430                                    let delimiter_trim = delimiter.trim_end();
 4431                                    let delimiter_line = snapshot
 4432                                        .chars_for_range(range.clone())
 4433                                        .skip(num_of_whitespaces)
 4434                                        .take(delimiter_trim.len())
 4435                                        .collect::<String>();
 4436                                    if delimiter_line.starts_with(delimiter_trim) {
 4437                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4438                                    } else {
 4439                                        false
 4440                                    }
 4441                                };
 4442
 4443                                let cursor_is_before_end_tag_if_exists = {
 4444                                    let mut char_position = 0u32;
 4445                                    let mut end_tag_offset = None;
 4446
 4447                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4448                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4449                                            let chars_before_match =
 4450                                                chunk[..byte_pos].chars().count() as u32;
 4451                                            end_tag_offset =
 4452                                                Some(char_position + chars_before_match);
 4453                                            break 'outer;
 4454                                        }
 4455                                        char_position += chunk.chars().count() as u32;
 4456                                    }
 4457
 4458                                    if let Some(end_tag_offset) = end_tag_offset {
 4459                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4460                                        if cursor_is_after_start_tag {
 4461                                            if cursor_is_before_end_tag {
 4462                                                insert_extra_newline = true;
 4463                                            }
 4464                                            let cursor_is_at_start_of_end_tag =
 4465                                                column == end_tag_offset;
 4466                                            if cursor_is_at_start_of_end_tag {
 4467                                                indent_on_extra_newline.len = (*len).into();
 4468                                            }
 4469                                        }
 4470                                        cursor_is_before_end_tag
 4471                                    } else {
 4472                                        true
 4473                                    }
 4474                                };
 4475
 4476                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4477                                    && cursor_is_before_end_tag_if_exists
 4478                                {
 4479                                    if cursor_is_after_start_tag {
 4480                                        indent_on_newline.len = (*len).into();
 4481                                    }
 4482                                    Some(delimiter.clone())
 4483                                } else {
 4484                                    None
 4485                                }
 4486                            });
 4487
 4488                            (
 4489                                comment_delimiter,
 4490                                doc_delimiter,
 4491                                insert_extra_newline,
 4492                                indent_on_newline,
 4493                                indent_on_extra_newline,
 4494                            )
 4495                        } else {
 4496                            (
 4497                                None,
 4498                                None,
 4499                                false,
 4500                                IndentSize::default(),
 4501                                IndentSize::default(),
 4502                            )
 4503                        };
 4504
 4505                        let prevent_auto_indent = doc_delimiter.is_some();
 4506                        let delimiter = comment_delimiter.or(doc_delimiter);
 4507
 4508                        let capacity_for_delimiter =
 4509                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4510                        let mut new_text = String::with_capacity(
 4511                            1 + capacity_for_delimiter
 4512                                + existing_indent.len as usize
 4513                                + indent_on_newline.len as usize
 4514                                + indent_on_extra_newline.len as usize,
 4515                        );
 4516                        new_text.push('\n');
 4517                        new_text.extend(existing_indent.chars());
 4518                        new_text.extend(indent_on_newline.chars());
 4519
 4520                        if let Some(delimiter) = &delimiter {
 4521                            new_text.push_str(delimiter);
 4522                        }
 4523
 4524                        if insert_extra_newline {
 4525                            new_text.push('\n');
 4526                            new_text.extend(existing_indent.chars());
 4527                            new_text.extend(indent_on_extra_newline.chars());
 4528                        }
 4529
 4530                        let anchor = buffer.anchor_after(end);
 4531                        let new_selection = selection.map(|_| anchor);
 4532                        (
 4533                            ((start..end, new_text), prevent_auto_indent),
 4534                            (insert_extra_newline, new_selection),
 4535                        )
 4536                    })
 4537                    .unzip()
 4538            };
 4539
 4540            let mut auto_indent_edits = Vec::new();
 4541            let mut edits = Vec::new();
 4542            for (edit, prevent_auto_indent) in edits_with_flags {
 4543                if prevent_auto_indent {
 4544                    edits.push(edit);
 4545                } else {
 4546                    auto_indent_edits.push(edit);
 4547                }
 4548            }
 4549            if !edits.is_empty() {
 4550                this.edit(edits, cx);
 4551            }
 4552            if !auto_indent_edits.is_empty() {
 4553                this.edit_with_autoindent(auto_indent_edits, cx);
 4554            }
 4555
 4556            let buffer = this.buffer.read(cx).snapshot(cx);
 4557            let new_selections = selection_info
 4558                .into_iter()
 4559                .map(|(extra_newline_inserted, new_selection)| {
 4560                    let mut cursor = new_selection.end.to_point(&buffer);
 4561                    if extra_newline_inserted {
 4562                        cursor.row -= 1;
 4563                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4564                    }
 4565                    new_selection.map(|_| cursor)
 4566                })
 4567                .collect();
 4568
 4569            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4570            this.refresh_inline_completion(true, false, window, cx);
 4571        });
 4572    }
 4573
 4574    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4575        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4576
 4577        let buffer = self.buffer.read(cx);
 4578        let snapshot = buffer.snapshot(cx);
 4579
 4580        let mut edits = Vec::new();
 4581        let mut rows = Vec::new();
 4582
 4583        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4584            let cursor = selection.head();
 4585            let row = cursor.row;
 4586
 4587            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4588
 4589            let newline = "\n".to_string();
 4590            edits.push((start_of_line..start_of_line, newline));
 4591
 4592            rows.push(row + rows_inserted as u32);
 4593        }
 4594
 4595        self.transact(window, cx, |editor, window, cx| {
 4596            editor.edit(edits, cx);
 4597
 4598            editor.change_selections(Default::default(), window, cx, |s| {
 4599                let mut index = 0;
 4600                s.move_cursors_with(|map, _, _| {
 4601                    let row = rows[index];
 4602                    index += 1;
 4603
 4604                    let point = Point::new(row, 0);
 4605                    let boundary = map.next_line_boundary(point).1;
 4606                    let clipped = map.clip_point(boundary, Bias::Left);
 4607
 4608                    (clipped, SelectionGoal::None)
 4609                });
 4610            });
 4611
 4612            let mut indent_edits = Vec::new();
 4613            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4614            for row in rows {
 4615                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4616                for (row, indent) in indents {
 4617                    if indent.len == 0 {
 4618                        continue;
 4619                    }
 4620
 4621                    let text = match indent.kind {
 4622                        IndentKind::Space => " ".repeat(indent.len as usize),
 4623                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4624                    };
 4625                    let point = Point::new(row.0, 0);
 4626                    indent_edits.push((point..point, text));
 4627                }
 4628            }
 4629            editor.edit(indent_edits, cx);
 4630        });
 4631    }
 4632
 4633    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4634        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4635
 4636        let buffer = self.buffer.read(cx);
 4637        let snapshot = buffer.snapshot(cx);
 4638
 4639        let mut edits = Vec::new();
 4640        let mut rows = Vec::new();
 4641        let mut rows_inserted = 0;
 4642
 4643        for selection in self.selections.all_adjusted(cx) {
 4644            let cursor = selection.head();
 4645            let row = cursor.row;
 4646
 4647            let point = Point::new(row + 1, 0);
 4648            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4649
 4650            let newline = "\n".to_string();
 4651            edits.push((start_of_line..start_of_line, newline));
 4652
 4653            rows_inserted += 1;
 4654            rows.push(row + rows_inserted);
 4655        }
 4656
 4657        self.transact(window, cx, |editor, window, cx| {
 4658            editor.edit(edits, cx);
 4659
 4660            editor.change_selections(Default::default(), window, cx, |s| {
 4661                let mut index = 0;
 4662                s.move_cursors_with(|map, _, _| {
 4663                    let row = rows[index];
 4664                    index += 1;
 4665
 4666                    let point = Point::new(row, 0);
 4667                    let boundary = map.next_line_boundary(point).1;
 4668                    let clipped = map.clip_point(boundary, Bias::Left);
 4669
 4670                    (clipped, SelectionGoal::None)
 4671                });
 4672            });
 4673
 4674            let mut indent_edits = Vec::new();
 4675            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4676            for row in rows {
 4677                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4678                for (row, indent) in indents {
 4679                    if indent.len == 0 {
 4680                        continue;
 4681                    }
 4682
 4683                    let text = match indent.kind {
 4684                        IndentKind::Space => " ".repeat(indent.len as usize),
 4685                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4686                    };
 4687                    let point = Point::new(row.0, 0);
 4688                    indent_edits.push((point..point, text));
 4689                }
 4690            }
 4691            editor.edit(indent_edits, cx);
 4692        });
 4693    }
 4694
 4695    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4696        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4697            original_indent_columns: Vec::new(),
 4698        });
 4699        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4700    }
 4701
 4702    fn insert_with_autoindent_mode(
 4703        &mut self,
 4704        text: &str,
 4705        autoindent_mode: Option<AutoindentMode>,
 4706        window: &mut Window,
 4707        cx: &mut Context<Self>,
 4708    ) {
 4709        if self.read_only(cx) {
 4710            return;
 4711        }
 4712
 4713        let text: Arc<str> = text.into();
 4714        self.transact(window, cx, |this, window, cx| {
 4715            let old_selections = this.selections.all_adjusted(cx);
 4716            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4717                let anchors = {
 4718                    let snapshot = buffer.read(cx);
 4719                    old_selections
 4720                        .iter()
 4721                        .map(|s| {
 4722                            let anchor = snapshot.anchor_after(s.head());
 4723                            s.map(|_| anchor)
 4724                        })
 4725                        .collect::<Vec<_>>()
 4726                };
 4727                buffer.edit(
 4728                    old_selections
 4729                        .iter()
 4730                        .map(|s| (s.start..s.end, text.clone())),
 4731                    autoindent_mode,
 4732                    cx,
 4733                );
 4734                anchors
 4735            });
 4736
 4737            this.change_selections(Default::default(), window, cx, |s| {
 4738                s.select_anchors(selection_anchors);
 4739            });
 4740
 4741            cx.notify();
 4742        });
 4743    }
 4744
 4745    fn trigger_completion_on_input(
 4746        &mut self,
 4747        text: &str,
 4748        trigger_in_words: bool,
 4749        window: &mut Window,
 4750        cx: &mut Context<Self>,
 4751    ) {
 4752        let completions_source = self
 4753            .context_menu
 4754            .borrow()
 4755            .as_ref()
 4756            .and_then(|menu| match menu {
 4757                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4758                CodeContextMenu::CodeActions(_) => None,
 4759            });
 4760
 4761        match completions_source {
 4762            Some(CompletionsMenuSource::Words) => {
 4763                self.show_word_completions(&ShowWordCompletions, window, cx)
 4764            }
 4765            Some(CompletionsMenuSource::Normal)
 4766            | Some(CompletionsMenuSource::SnippetChoices)
 4767            | None
 4768                if self.is_completion_trigger(
 4769                    text,
 4770                    trigger_in_words,
 4771                    completions_source.is_some(),
 4772                    cx,
 4773                ) =>
 4774            {
 4775                self.show_completions(
 4776                    &ShowCompletions {
 4777                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4778                    },
 4779                    window,
 4780                    cx,
 4781                )
 4782            }
 4783            _ => {
 4784                self.hide_context_menu(window, cx);
 4785            }
 4786        }
 4787    }
 4788
 4789    fn is_completion_trigger(
 4790        &self,
 4791        text: &str,
 4792        trigger_in_words: bool,
 4793        menu_is_open: bool,
 4794        cx: &mut Context<Self>,
 4795    ) -> bool {
 4796        let position = self.selections.newest_anchor().head();
 4797        let multibuffer = self.buffer.read(cx);
 4798        let Some(buffer) = position
 4799            .buffer_id
 4800            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4801        else {
 4802            return false;
 4803        };
 4804
 4805        if let Some(completion_provider) = &self.completion_provider {
 4806            completion_provider.is_completion_trigger(
 4807                &buffer,
 4808                position.text_anchor,
 4809                text,
 4810                trigger_in_words,
 4811                menu_is_open,
 4812                cx,
 4813            )
 4814        } else {
 4815            false
 4816        }
 4817    }
 4818
 4819    /// If any empty selections is touching the start of its innermost containing autoclose
 4820    /// region, expand it to select the brackets.
 4821    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4822        let selections = self.selections.all::<usize>(cx);
 4823        let buffer = self.buffer.read(cx).read(cx);
 4824        let new_selections = self
 4825            .selections_with_autoclose_regions(selections, &buffer)
 4826            .map(|(mut selection, region)| {
 4827                if !selection.is_empty() {
 4828                    return selection;
 4829                }
 4830
 4831                if let Some(region) = region {
 4832                    let mut range = region.range.to_offset(&buffer);
 4833                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4834                        range.start -= region.pair.start.len();
 4835                        if buffer.contains_str_at(range.start, &region.pair.start)
 4836                            && buffer.contains_str_at(range.end, &region.pair.end)
 4837                        {
 4838                            range.end += region.pair.end.len();
 4839                            selection.start = range.start;
 4840                            selection.end = range.end;
 4841
 4842                            return selection;
 4843                        }
 4844                    }
 4845                }
 4846
 4847                let always_treat_brackets_as_autoclosed = buffer
 4848                    .language_settings_at(selection.start, cx)
 4849                    .always_treat_brackets_as_autoclosed;
 4850
 4851                if !always_treat_brackets_as_autoclosed {
 4852                    return selection;
 4853                }
 4854
 4855                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4856                    for (pair, enabled) in scope.brackets() {
 4857                        if !enabled || !pair.close {
 4858                            continue;
 4859                        }
 4860
 4861                        if buffer.contains_str_at(selection.start, &pair.end) {
 4862                            let pair_start_len = pair.start.len();
 4863                            if buffer.contains_str_at(
 4864                                selection.start.saturating_sub(pair_start_len),
 4865                                &pair.start,
 4866                            ) {
 4867                                selection.start -= pair_start_len;
 4868                                selection.end += pair.end.len();
 4869
 4870                                return selection;
 4871                            }
 4872                        }
 4873                    }
 4874                }
 4875
 4876                selection
 4877            })
 4878            .collect();
 4879
 4880        drop(buffer);
 4881        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4882            selections.select(new_selections)
 4883        });
 4884    }
 4885
 4886    /// Iterate the given selections, and for each one, find the smallest surrounding
 4887    /// autoclose region. This uses the ordering of the selections and the autoclose
 4888    /// regions to avoid repeated comparisons.
 4889    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4890        &'a self,
 4891        selections: impl IntoIterator<Item = Selection<D>>,
 4892        buffer: &'a MultiBufferSnapshot,
 4893    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4894        let mut i = 0;
 4895        let mut regions = self.autoclose_regions.as_slice();
 4896        selections.into_iter().map(move |selection| {
 4897            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4898
 4899            let mut enclosing = None;
 4900            while let Some(pair_state) = regions.get(i) {
 4901                if pair_state.range.end.to_offset(buffer) < range.start {
 4902                    regions = &regions[i + 1..];
 4903                    i = 0;
 4904                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4905                    break;
 4906                } else {
 4907                    if pair_state.selection_id == selection.id {
 4908                        enclosing = Some(pair_state);
 4909                    }
 4910                    i += 1;
 4911                }
 4912            }
 4913
 4914            (selection, enclosing)
 4915        })
 4916    }
 4917
 4918    /// Remove any autoclose regions that no longer contain their selection.
 4919    fn invalidate_autoclose_regions(
 4920        &mut self,
 4921        mut selections: &[Selection<Anchor>],
 4922        buffer: &MultiBufferSnapshot,
 4923    ) {
 4924        self.autoclose_regions.retain(|state| {
 4925            let mut i = 0;
 4926            while let Some(selection) = selections.get(i) {
 4927                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4928                    selections = &selections[1..];
 4929                    continue;
 4930                }
 4931                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4932                    break;
 4933                }
 4934                if selection.id == state.selection_id {
 4935                    return true;
 4936                } else {
 4937                    i += 1;
 4938                }
 4939            }
 4940            false
 4941        });
 4942    }
 4943
 4944    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4945        let offset = position.to_offset(buffer);
 4946        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4947        if offset > word_range.start && kind == Some(CharKind::Word) {
 4948            Some(
 4949                buffer
 4950                    .text_for_range(word_range.start..offset)
 4951                    .collect::<String>(),
 4952            )
 4953        } else {
 4954            None
 4955        }
 4956    }
 4957
 4958    pub fn toggle_inline_values(
 4959        &mut self,
 4960        _: &ToggleInlineValues,
 4961        _: &mut Window,
 4962        cx: &mut Context<Self>,
 4963    ) {
 4964        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4965
 4966        self.refresh_inline_values(cx);
 4967    }
 4968
 4969    pub fn toggle_inlay_hints(
 4970        &mut self,
 4971        _: &ToggleInlayHints,
 4972        _: &mut Window,
 4973        cx: &mut Context<Self>,
 4974    ) {
 4975        self.refresh_inlay_hints(
 4976            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4977            cx,
 4978        );
 4979    }
 4980
 4981    pub fn inlay_hints_enabled(&self) -> bool {
 4982        self.inlay_hint_cache.enabled
 4983    }
 4984
 4985    pub fn inline_values_enabled(&self) -> bool {
 4986        self.inline_value_cache.enabled
 4987    }
 4988
 4989    #[cfg(any(test, feature = "test-support"))]
 4990    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4991        self.display_map
 4992            .read(cx)
 4993            .current_inlays()
 4994            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4995            .cloned()
 4996            .collect()
 4997    }
 4998
 4999    #[cfg(any(test, feature = "test-support"))]
 5000    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5001        self.display_map
 5002            .read(cx)
 5003            .current_inlays()
 5004            .cloned()
 5005            .collect()
 5006    }
 5007
 5008    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5009        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5010            return;
 5011        }
 5012
 5013        let reason_description = reason.description();
 5014        let ignore_debounce = matches!(
 5015            reason,
 5016            InlayHintRefreshReason::SettingsChange(_)
 5017                | InlayHintRefreshReason::Toggle(_)
 5018                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5019                | InlayHintRefreshReason::ModifiersChanged(_)
 5020        );
 5021        let (invalidate_cache, required_languages) = match reason {
 5022            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5023                match self.inlay_hint_cache.modifiers_override(enabled) {
 5024                    Some(enabled) => {
 5025                        if enabled {
 5026                            (InvalidationStrategy::RefreshRequested, None)
 5027                        } else {
 5028                            self.splice_inlays(
 5029                                &self
 5030                                    .visible_inlay_hints(cx)
 5031                                    .iter()
 5032                                    .map(|inlay| inlay.id)
 5033                                    .collect::<Vec<InlayId>>(),
 5034                                Vec::new(),
 5035                                cx,
 5036                            );
 5037                            return;
 5038                        }
 5039                    }
 5040                    None => return,
 5041                }
 5042            }
 5043            InlayHintRefreshReason::Toggle(enabled) => {
 5044                if self.inlay_hint_cache.toggle(enabled) {
 5045                    if enabled {
 5046                        (InvalidationStrategy::RefreshRequested, None)
 5047                    } else {
 5048                        self.splice_inlays(
 5049                            &self
 5050                                .visible_inlay_hints(cx)
 5051                                .iter()
 5052                                .map(|inlay| inlay.id)
 5053                                .collect::<Vec<InlayId>>(),
 5054                            Vec::new(),
 5055                            cx,
 5056                        );
 5057                        return;
 5058                    }
 5059                } else {
 5060                    return;
 5061                }
 5062            }
 5063            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5064                match self.inlay_hint_cache.update_settings(
 5065                    &self.buffer,
 5066                    new_settings,
 5067                    self.visible_inlay_hints(cx),
 5068                    cx,
 5069                ) {
 5070                    ControlFlow::Break(Some(InlaySplice {
 5071                        to_remove,
 5072                        to_insert,
 5073                    })) => {
 5074                        self.splice_inlays(&to_remove, to_insert, cx);
 5075                        return;
 5076                    }
 5077                    ControlFlow::Break(None) => return,
 5078                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5079                }
 5080            }
 5081            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5082                if let Some(InlaySplice {
 5083                    to_remove,
 5084                    to_insert,
 5085                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5086                {
 5087                    self.splice_inlays(&to_remove, to_insert, cx);
 5088                }
 5089                self.display_map.update(cx, |display_map, _| {
 5090                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5091                });
 5092                return;
 5093            }
 5094            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5095            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5096                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5097            }
 5098            InlayHintRefreshReason::RefreshRequested => {
 5099                (InvalidationStrategy::RefreshRequested, None)
 5100            }
 5101        };
 5102
 5103        if let Some(InlaySplice {
 5104            to_remove,
 5105            to_insert,
 5106        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5107            reason_description,
 5108            self.visible_excerpts(required_languages.as_ref(), cx),
 5109            invalidate_cache,
 5110            ignore_debounce,
 5111            cx,
 5112        ) {
 5113            self.splice_inlays(&to_remove, to_insert, cx);
 5114        }
 5115    }
 5116
 5117    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5118        self.display_map
 5119            .read(cx)
 5120            .current_inlays()
 5121            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5122            .cloned()
 5123            .collect()
 5124    }
 5125
 5126    pub fn visible_excerpts(
 5127        &self,
 5128        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5129        cx: &mut Context<Editor>,
 5130    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5131        let Some(project) = self.project.as_ref() else {
 5132            return HashMap::default();
 5133        };
 5134        let project = project.read(cx);
 5135        let multi_buffer = self.buffer().read(cx);
 5136        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5137        let multi_buffer_visible_start = self
 5138            .scroll_manager
 5139            .anchor()
 5140            .anchor
 5141            .to_point(&multi_buffer_snapshot);
 5142        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5143            multi_buffer_visible_start
 5144                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5145            Bias::Left,
 5146        );
 5147        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5148        multi_buffer_snapshot
 5149            .range_to_buffer_ranges(multi_buffer_visible_range)
 5150            .into_iter()
 5151            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5152            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5153                let buffer_file = project::File::from_dyn(buffer.file())?;
 5154                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5155                let worktree_entry = buffer_worktree
 5156                    .read(cx)
 5157                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5158                if worktree_entry.is_ignored {
 5159                    return None;
 5160                }
 5161
 5162                let language = buffer.language()?;
 5163                if let Some(restrict_to_languages) = restrict_to_languages {
 5164                    if !restrict_to_languages.contains(language) {
 5165                        return None;
 5166                    }
 5167                }
 5168                Some((
 5169                    excerpt_id,
 5170                    (
 5171                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5172                        buffer.version().clone(),
 5173                        excerpt_visible_range,
 5174                    ),
 5175                ))
 5176            })
 5177            .collect()
 5178    }
 5179
 5180    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5181        TextLayoutDetails {
 5182            text_system: window.text_system().clone(),
 5183            editor_style: self.style.clone().unwrap(),
 5184            rem_size: window.rem_size(),
 5185            scroll_anchor: self.scroll_manager.anchor(),
 5186            visible_rows: self.visible_line_count(),
 5187            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5188        }
 5189    }
 5190
 5191    pub fn splice_inlays(
 5192        &self,
 5193        to_remove: &[InlayId],
 5194        to_insert: Vec<Inlay>,
 5195        cx: &mut Context<Self>,
 5196    ) {
 5197        self.display_map.update(cx, |display_map, cx| {
 5198            display_map.splice_inlays(to_remove, to_insert, cx)
 5199        });
 5200        cx.notify();
 5201    }
 5202
 5203    fn trigger_on_type_formatting(
 5204        &self,
 5205        input: String,
 5206        window: &mut Window,
 5207        cx: &mut Context<Self>,
 5208    ) -> Option<Task<Result<()>>> {
 5209        if input.len() != 1 {
 5210            return None;
 5211        }
 5212
 5213        let project = self.project.as_ref()?;
 5214        let position = self.selections.newest_anchor().head();
 5215        let (buffer, buffer_position) = self
 5216            .buffer
 5217            .read(cx)
 5218            .text_anchor_for_position(position, cx)?;
 5219
 5220        let settings = language_settings::language_settings(
 5221            buffer
 5222                .read(cx)
 5223                .language_at(buffer_position)
 5224                .map(|l| l.name()),
 5225            buffer.read(cx).file(),
 5226            cx,
 5227        );
 5228        if !settings.use_on_type_format {
 5229            return None;
 5230        }
 5231
 5232        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5233        // hence we do LSP request & edit on host side only — add formats to host's history.
 5234        let push_to_lsp_host_history = true;
 5235        // If this is not the host, append its history with new edits.
 5236        let push_to_client_history = project.read(cx).is_via_collab();
 5237
 5238        let on_type_formatting = project.update(cx, |project, cx| {
 5239            project.on_type_format(
 5240                buffer.clone(),
 5241                buffer_position,
 5242                input,
 5243                push_to_lsp_host_history,
 5244                cx,
 5245            )
 5246        });
 5247        Some(cx.spawn_in(window, async move |editor, cx| {
 5248            if let Some(transaction) = on_type_formatting.await? {
 5249                if push_to_client_history {
 5250                    buffer
 5251                        .update(cx, |buffer, _| {
 5252                            buffer.push_transaction(transaction, Instant::now());
 5253                            buffer.finalize_last_transaction();
 5254                        })
 5255                        .ok();
 5256                }
 5257                editor.update(cx, |editor, cx| {
 5258                    editor.refresh_document_highlights(cx);
 5259                })?;
 5260            }
 5261            Ok(())
 5262        }))
 5263    }
 5264
 5265    pub fn show_word_completions(
 5266        &mut self,
 5267        _: &ShowWordCompletions,
 5268        window: &mut Window,
 5269        cx: &mut Context<Self>,
 5270    ) {
 5271        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5272    }
 5273
 5274    pub fn show_completions(
 5275        &mut self,
 5276        options: &ShowCompletions,
 5277        window: &mut Window,
 5278        cx: &mut Context<Self>,
 5279    ) {
 5280        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5281    }
 5282
 5283    fn open_or_update_completions_menu(
 5284        &mut self,
 5285        requested_source: Option<CompletionsMenuSource>,
 5286        trigger: Option<&str>,
 5287        window: &mut Window,
 5288        cx: &mut Context<Self>,
 5289    ) {
 5290        if self.pending_rename.is_some() {
 5291            return;
 5292        }
 5293
 5294        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5295
 5296        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5297        // inserted and selected. To handle that case, the start of the selection is used so that
 5298        // the menu starts with all choices.
 5299        let position = self
 5300            .selections
 5301            .newest_anchor()
 5302            .start
 5303            .bias_right(&multibuffer_snapshot);
 5304        if position.diff_base_anchor.is_some() {
 5305            return;
 5306        }
 5307        let (buffer, buffer_position) =
 5308            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5309                output
 5310            } else {
 5311                return;
 5312            };
 5313        let buffer_snapshot = buffer.read(cx).snapshot();
 5314
 5315        let query: Option<Arc<String>> =
 5316            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5317
 5318        drop(multibuffer_snapshot);
 5319
 5320        let provider = match requested_source {
 5321            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5322            Some(CompletionsMenuSource::Words) => None,
 5323            Some(CompletionsMenuSource::SnippetChoices) => {
 5324                log::error!("bug: SnippetChoices requested_source is not handled");
 5325                None
 5326            }
 5327        };
 5328
 5329        let sort_completions = provider
 5330            .as_ref()
 5331            .map_or(false, |provider| provider.sort_completions());
 5332
 5333        let filter_completions = provider
 5334            .as_ref()
 5335            .map_or(true, |provider| provider.filter_completions());
 5336
 5337        let trigger_kind = match trigger {
 5338            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5339                CompletionTriggerKind::TRIGGER_CHARACTER
 5340            }
 5341            _ => CompletionTriggerKind::INVOKED,
 5342        };
 5343        let completion_context = CompletionContext {
 5344            trigger_character: trigger.and_then(|trigger| {
 5345                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5346                    Some(String::from(trigger))
 5347                } else {
 5348                    None
 5349                }
 5350            }),
 5351            trigger_kind,
 5352        };
 5353
 5354        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5355        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5356        // involve trigger chars, so this is skipped in that case.
 5357        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5358        {
 5359            let menu_is_open = matches!(
 5360                self.context_menu.borrow().as_ref(),
 5361                Some(CodeContextMenu::Completions(_))
 5362            );
 5363            if menu_is_open {
 5364                self.hide_context_menu(window, cx);
 5365            }
 5366        }
 5367
 5368        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5369            if filter_completions {
 5370                menu.filter(query.clone(), provider.clone(), window, cx);
 5371            }
 5372            // When `is_incomplete` is false, no need to re-query completions when the current query
 5373            // is a suffix of the initial query.
 5374            if !menu.is_incomplete {
 5375                // If the new query is a suffix of the old query (typing more characters) and
 5376                // the previous result was complete, the existing completions can be filtered.
 5377                //
 5378                // Note that this is always true for snippet completions.
 5379                let query_matches = match (&menu.initial_query, &query) {
 5380                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5381                    (None, _) => true,
 5382                    _ => false,
 5383                };
 5384                if query_matches {
 5385                    let position_matches = if menu.initial_position == position {
 5386                        true
 5387                    } else {
 5388                        let snapshot = self.buffer.read(cx).read(cx);
 5389                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5390                    };
 5391                    if position_matches {
 5392                        return;
 5393                    }
 5394                }
 5395            }
 5396        };
 5397
 5398        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5399            buffer_snapshot.surrounding_word(buffer_position)
 5400        {
 5401            let word_to_exclude = buffer_snapshot
 5402                .text_for_range(word_range.clone())
 5403                .collect::<String>();
 5404            (
 5405                buffer_snapshot.anchor_before(word_range.start)
 5406                    ..buffer_snapshot.anchor_after(buffer_position),
 5407                Some(word_to_exclude),
 5408            )
 5409        } else {
 5410            (buffer_position..buffer_position, None)
 5411        };
 5412
 5413        let language = buffer_snapshot
 5414            .language_at(buffer_position)
 5415            .map(|language| language.name());
 5416
 5417        let completion_settings =
 5418            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5419
 5420        let show_completion_documentation = buffer_snapshot
 5421            .settings_at(buffer_position, cx)
 5422            .show_completion_documentation;
 5423
 5424        // The document can be large, so stay in reasonable bounds when searching for words,
 5425        // otherwise completion pop-up might be slow to appear.
 5426        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5427        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5428        let min_word_search = buffer_snapshot.clip_point(
 5429            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5430            Bias::Left,
 5431        );
 5432        let max_word_search = buffer_snapshot.clip_point(
 5433            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5434            Bias::Right,
 5435        );
 5436        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5437            ..buffer_snapshot.point_to_offset(max_word_search);
 5438
 5439        let skip_digits = query
 5440            .as_ref()
 5441            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5442
 5443        let (mut words, provider_responses) = match &provider {
 5444            Some(provider) => {
 5445                let provider_responses = provider.completions(
 5446                    position.excerpt_id,
 5447                    &buffer,
 5448                    buffer_position,
 5449                    completion_context,
 5450                    window,
 5451                    cx,
 5452                );
 5453
 5454                let words = match completion_settings.words {
 5455                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5456                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5457                        .background_spawn(async move {
 5458                            buffer_snapshot.words_in_range(WordsQuery {
 5459                                fuzzy_contents: None,
 5460                                range: word_search_range,
 5461                                skip_digits,
 5462                            })
 5463                        }),
 5464                };
 5465
 5466                (words, provider_responses)
 5467            }
 5468            None => (
 5469                cx.background_spawn(async move {
 5470                    buffer_snapshot.words_in_range(WordsQuery {
 5471                        fuzzy_contents: None,
 5472                        range: word_search_range,
 5473                        skip_digits,
 5474                    })
 5475                }),
 5476                Task::ready(Ok(Vec::new())),
 5477            ),
 5478        };
 5479
 5480        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5481
 5482        let id = post_inc(&mut self.next_completion_id);
 5483        let task = cx.spawn_in(window, async move |editor, cx| {
 5484            let Ok(()) = editor.update(cx, |this, _| {
 5485                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5486            }) else {
 5487                return;
 5488            };
 5489
 5490            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5491            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5492            let mut completions = Vec::new();
 5493            let mut is_incomplete = false;
 5494            if let Some(provider_responses) = provider_responses.await.log_err() {
 5495                if !provider_responses.is_empty() {
 5496                    for response in provider_responses {
 5497                        completions.extend(response.completions);
 5498                        is_incomplete = is_incomplete || response.is_incomplete;
 5499                    }
 5500                    if completion_settings.words == WordsCompletionMode::Fallback {
 5501                        words = Task::ready(BTreeMap::default());
 5502                    }
 5503                }
 5504            }
 5505
 5506            let mut words = words.await;
 5507            if let Some(word_to_exclude) = &word_to_exclude {
 5508                words.remove(word_to_exclude);
 5509            }
 5510            for lsp_completion in &completions {
 5511                words.remove(&lsp_completion.new_text);
 5512            }
 5513            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5514                replace_range: word_replace_range.clone(),
 5515                new_text: word.clone(),
 5516                label: CodeLabel::plain(word, None),
 5517                icon_path: None,
 5518                documentation: None,
 5519                source: CompletionSource::BufferWord {
 5520                    word_range,
 5521                    resolved: false,
 5522                },
 5523                insert_text_mode: Some(InsertTextMode::AS_IS),
 5524                confirm: None,
 5525            }));
 5526
 5527            let menu = if completions.is_empty() {
 5528                None
 5529            } else {
 5530                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5531                    let languages = editor
 5532                        .workspace
 5533                        .as_ref()
 5534                        .and_then(|(workspace, _)| workspace.upgrade())
 5535                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5536                    let menu = CompletionsMenu::new(
 5537                        id,
 5538                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5539                        sort_completions,
 5540                        show_completion_documentation,
 5541                        position,
 5542                        query.clone(),
 5543                        is_incomplete,
 5544                        buffer.clone(),
 5545                        completions.into(),
 5546                        snippet_sort_order,
 5547                        languages,
 5548                        language,
 5549                        cx,
 5550                    );
 5551
 5552                    let query = if filter_completions { query } else { None };
 5553                    let matches_task = if let Some(query) = query {
 5554                        menu.do_async_filtering(query, cx)
 5555                    } else {
 5556                        Task::ready(menu.unfiltered_matches())
 5557                    };
 5558                    (menu, matches_task)
 5559                }) else {
 5560                    return;
 5561                };
 5562
 5563                let matches = matches_task.await;
 5564
 5565                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5566                    // Newer menu already set, so exit.
 5567                    match editor.context_menu.borrow().as_ref() {
 5568                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5569                            if prev_menu.id > id {
 5570                                return;
 5571                            }
 5572                        }
 5573                        _ => {}
 5574                    };
 5575
 5576                    // Only valid to take prev_menu because it the new menu is immediately set
 5577                    // below, or the menu is hidden.
 5578                    match editor.context_menu.borrow_mut().take() {
 5579                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5580                            let position_matches =
 5581                                if prev_menu.initial_position == menu.initial_position {
 5582                                    true
 5583                                } else {
 5584                                    let snapshot = editor.buffer.read(cx).read(cx);
 5585                                    prev_menu.initial_position.to_offset(&snapshot)
 5586                                        == menu.initial_position.to_offset(&snapshot)
 5587                                };
 5588                            if position_matches {
 5589                                // Preserve markdown cache before `set_filter_results` because it will
 5590                                // try to populate the documentation cache.
 5591                                menu.preserve_markdown_cache(prev_menu);
 5592                            }
 5593                        }
 5594                        _ => {}
 5595                    };
 5596
 5597                    menu.set_filter_results(matches, provider, window, cx);
 5598                }) else {
 5599                    return;
 5600                };
 5601
 5602                menu.visible().then_some(menu)
 5603            };
 5604
 5605            editor
 5606                .update_in(cx, |editor, window, cx| {
 5607                    if editor.focus_handle.is_focused(window) {
 5608                        if let Some(menu) = menu {
 5609                            *editor.context_menu.borrow_mut() =
 5610                                Some(CodeContextMenu::Completions(menu));
 5611
 5612                            crate::hover_popover::hide_hover(editor, cx);
 5613                            if editor.show_edit_predictions_in_menu() {
 5614                                editor.update_visible_inline_completion(window, cx);
 5615                            } else {
 5616                                editor.discard_inline_completion(false, cx);
 5617                            }
 5618
 5619                            cx.notify();
 5620                            return;
 5621                        }
 5622                    }
 5623
 5624                    if editor.completion_tasks.len() <= 1 {
 5625                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5626                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5627                        // If it was already hidden and we don't show inline completions in the menu, we should
 5628                        // also show the inline-completion when available.
 5629                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5630                            editor.update_visible_inline_completion(window, cx);
 5631                        }
 5632                    }
 5633                })
 5634                .ok();
 5635        });
 5636
 5637        self.completion_tasks.push((id, task));
 5638    }
 5639
 5640    #[cfg(feature = "test-support")]
 5641    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5642        let menu = self.context_menu.borrow();
 5643        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5644            let completions = menu.completions.borrow();
 5645            Some(completions.to_vec())
 5646        } else {
 5647            None
 5648        }
 5649    }
 5650
 5651    pub fn with_completions_menu_matching_id<R>(
 5652        &self,
 5653        id: CompletionId,
 5654        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5655    ) -> R {
 5656        let mut context_menu = self.context_menu.borrow_mut();
 5657        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5658            return f(None);
 5659        };
 5660        if completions_menu.id != id {
 5661            return f(None);
 5662        }
 5663        f(Some(completions_menu))
 5664    }
 5665
 5666    pub fn confirm_completion(
 5667        &mut self,
 5668        action: &ConfirmCompletion,
 5669        window: &mut Window,
 5670        cx: &mut Context<Self>,
 5671    ) -> Option<Task<Result<()>>> {
 5672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5673        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5674    }
 5675
 5676    pub fn confirm_completion_insert(
 5677        &mut self,
 5678        _: &ConfirmCompletionInsert,
 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(None, CompletionIntent::CompleteWithInsert, window, cx)
 5684    }
 5685
 5686    pub fn confirm_completion_replace(
 5687        &mut self,
 5688        _: &ConfirmCompletionReplace,
 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::CompleteWithReplace, window, cx)
 5694    }
 5695
 5696    pub fn compose_completion(
 5697        &mut self,
 5698        action: &ComposeCompletion,
 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(action.item_ix, CompletionIntent::Compose, window, cx)
 5704    }
 5705
 5706    fn do_completion(
 5707        &mut self,
 5708        item_ix: Option<usize>,
 5709        intent: CompletionIntent,
 5710        window: &mut Window,
 5711        cx: &mut Context<Editor>,
 5712    ) -> Option<Task<Result<()>>> {
 5713        use language::ToOffset as _;
 5714
 5715        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5716        else {
 5717            return None;
 5718        };
 5719
 5720        let candidate_id = {
 5721            let entries = completions_menu.entries.borrow();
 5722            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5723            if self.show_edit_predictions_in_menu() {
 5724                self.discard_inline_completion(true, cx);
 5725            }
 5726            mat.candidate_id
 5727        };
 5728
 5729        let completion = completions_menu
 5730            .completions
 5731            .borrow()
 5732            .get(candidate_id)?
 5733            .clone();
 5734        cx.stop_propagation();
 5735
 5736        let buffer_handle = completions_menu.buffer.clone();
 5737
 5738        let CompletionEdit {
 5739            new_text,
 5740            snippet,
 5741            replace_range,
 5742        } = process_completion_for_edit(
 5743            &completion,
 5744            intent,
 5745            &buffer_handle,
 5746            &completions_menu.initial_position.text_anchor,
 5747            cx,
 5748        );
 5749
 5750        let buffer = buffer_handle.read(cx);
 5751        let snapshot = self.buffer.read(cx).snapshot(cx);
 5752        let newest_anchor = self.selections.newest_anchor();
 5753        let replace_range_multibuffer = {
 5754            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5755            let multibuffer_anchor = snapshot
 5756                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5757                .unwrap()
 5758                ..snapshot
 5759                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5760                    .unwrap();
 5761            multibuffer_anchor.start.to_offset(&snapshot)
 5762                ..multibuffer_anchor.end.to_offset(&snapshot)
 5763        };
 5764        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5765            return None;
 5766        }
 5767
 5768        let old_text = buffer
 5769            .text_for_range(replace_range.clone())
 5770            .collect::<String>();
 5771        let lookbehind = newest_anchor
 5772            .start
 5773            .text_anchor
 5774            .to_offset(buffer)
 5775            .saturating_sub(replace_range.start);
 5776        let lookahead = replace_range
 5777            .end
 5778            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5779        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5780        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5781
 5782        let selections = self.selections.all::<usize>(cx);
 5783        let mut ranges = Vec::new();
 5784        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5785
 5786        for selection in &selections {
 5787            let range = if selection.id == newest_anchor.id {
 5788                replace_range_multibuffer.clone()
 5789            } else {
 5790                let mut range = selection.range();
 5791
 5792                // if prefix is present, don't duplicate it
 5793                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5794                    range.start = range.start.saturating_sub(lookbehind);
 5795
 5796                    // if suffix is also present, mimic the newest cursor and replace it
 5797                    if selection.id != newest_anchor.id
 5798                        && snapshot.contains_str_at(range.end, suffix)
 5799                    {
 5800                        range.end += lookahead;
 5801                    }
 5802                }
 5803                range
 5804            };
 5805
 5806            ranges.push(range.clone());
 5807
 5808            if !self.linked_edit_ranges.is_empty() {
 5809                let start_anchor = snapshot.anchor_before(range.start);
 5810                let end_anchor = snapshot.anchor_after(range.end);
 5811                if let Some(ranges) = self
 5812                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5813                {
 5814                    for (buffer, edits) in ranges {
 5815                        linked_edits
 5816                            .entry(buffer.clone())
 5817                            .or_default()
 5818                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5819                    }
 5820                }
 5821            }
 5822        }
 5823
 5824        let common_prefix_len = old_text
 5825            .chars()
 5826            .zip(new_text.chars())
 5827            .take_while(|(a, b)| a == b)
 5828            .map(|(a, _)| a.len_utf8())
 5829            .sum::<usize>();
 5830
 5831        cx.emit(EditorEvent::InputHandled {
 5832            utf16_range_to_replace: None,
 5833            text: new_text[common_prefix_len..].into(),
 5834        });
 5835
 5836        self.transact(window, cx, |this, window, cx| {
 5837            if let Some(mut snippet) = snippet {
 5838                snippet.text = new_text.to_string();
 5839                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5840            } else {
 5841                this.buffer.update(cx, |buffer, cx| {
 5842                    let auto_indent = match completion.insert_text_mode {
 5843                        Some(InsertTextMode::AS_IS) => None,
 5844                        _ => this.autoindent_mode.clone(),
 5845                    };
 5846                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5847                    buffer.edit(edits, auto_indent, cx);
 5848                });
 5849            }
 5850            for (buffer, edits) in linked_edits {
 5851                buffer.update(cx, |buffer, cx| {
 5852                    let snapshot = buffer.snapshot();
 5853                    let edits = edits
 5854                        .into_iter()
 5855                        .map(|(range, text)| {
 5856                            use text::ToPoint as TP;
 5857                            let end_point = TP::to_point(&range.end, &snapshot);
 5858                            let start_point = TP::to_point(&range.start, &snapshot);
 5859                            (start_point..end_point, text)
 5860                        })
 5861                        .sorted_by_key(|(range, _)| range.start);
 5862                    buffer.edit(edits, None, cx);
 5863                })
 5864            }
 5865
 5866            this.refresh_inline_completion(true, false, window, cx);
 5867        });
 5868
 5869        let show_new_completions_on_confirm = completion
 5870            .confirm
 5871            .as_ref()
 5872            .map_or(false, |confirm| confirm(intent, window, cx));
 5873        if show_new_completions_on_confirm {
 5874            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5875        }
 5876
 5877        let provider = self.completion_provider.as_ref()?;
 5878        drop(completion);
 5879        let apply_edits = provider.apply_additional_edits_for_completion(
 5880            buffer_handle,
 5881            completions_menu.completions.clone(),
 5882            candidate_id,
 5883            true,
 5884            cx,
 5885        );
 5886
 5887        let editor_settings = EditorSettings::get_global(cx);
 5888        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5889            // After the code completion is finished, users often want to know what signatures are needed.
 5890            // so we should automatically call signature_help
 5891            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5892        }
 5893
 5894        Some(cx.foreground_executor().spawn(async move {
 5895            apply_edits.await?;
 5896            Ok(())
 5897        }))
 5898    }
 5899
 5900    pub fn toggle_code_actions(
 5901        &mut self,
 5902        action: &ToggleCodeActions,
 5903        window: &mut Window,
 5904        cx: &mut Context<Self>,
 5905    ) {
 5906        let quick_launch = action.quick_launch;
 5907        let mut context_menu = self.context_menu.borrow_mut();
 5908        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5909            if code_actions.deployed_from == action.deployed_from {
 5910                // Toggle if we're selecting the same one
 5911                *context_menu = None;
 5912                cx.notify();
 5913                return;
 5914            } else {
 5915                // Otherwise, clear it and start a new one
 5916                *context_menu = None;
 5917                cx.notify();
 5918            }
 5919        }
 5920        drop(context_menu);
 5921        let snapshot = self.snapshot(window, cx);
 5922        let deployed_from = action.deployed_from.clone();
 5923        let action = action.clone();
 5924        self.completion_tasks.clear();
 5925        self.discard_inline_completion(false, cx);
 5926
 5927        let multibuffer_point = match &action.deployed_from {
 5928            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5929                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5930            }
 5931            _ => self.selections.newest::<Point>(cx).head(),
 5932        };
 5933        let Some((buffer, buffer_row)) = snapshot
 5934            .buffer_snapshot
 5935            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5936            .and_then(|(buffer_snapshot, range)| {
 5937                self.buffer()
 5938                    .read(cx)
 5939                    .buffer(buffer_snapshot.remote_id())
 5940                    .map(|buffer| (buffer, range.start.row))
 5941            })
 5942        else {
 5943            return;
 5944        };
 5945        let buffer_id = buffer.read(cx).remote_id();
 5946        let tasks = self
 5947            .tasks
 5948            .get(&(buffer_id, buffer_row))
 5949            .map(|t| Arc::new(t.to_owned()));
 5950
 5951        if !self.focus_handle.is_focused(window) {
 5952            return;
 5953        }
 5954        let project = self.project.clone();
 5955
 5956        let code_actions_task = match deployed_from {
 5957            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5958            _ => self.code_actions(buffer_row, window, cx),
 5959        };
 5960
 5961        let runnable_task = match deployed_from {
 5962            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5963            _ => {
 5964                let mut task_context_task = Task::ready(None);
 5965                if let Some(tasks) = &tasks {
 5966                    if let Some(project) = project {
 5967                        task_context_task =
 5968                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5969                    }
 5970                }
 5971
 5972                cx.spawn_in(window, {
 5973                    let buffer = buffer.clone();
 5974                    async move |editor, cx| {
 5975                        let task_context = task_context_task.await;
 5976
 5977                        let resolved_tasks =
 5978                            tasks
 5979                                .zip(task_context.clone())
 5980                                .map(|(tasks, task_context)| ResolvedTasks {
 5981                                    templates: tasks.resolve(&task_context).collect(),
 5982                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5983                                        multibuffer_point.row,
 5984                                        tasks.column,
 5985                                    )),
 5986                                });
 5987                        let debug_scenarios = editor
 5988                            .update(cx, |editor, cx| {
 5989                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5990                            })?
 5991                            .await;
 5992                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5993                    }
 5994                })
 5995            }
 5996        };
 5997
 5998        cx.spawn_in(window, async move |editor, cx| {
 5999            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6000            let code_actions = code_actions_task.await;
 6001            let spawn_straight_away = quick_launch
 6002                && resolved_tasks
 6003                    .as_ref()
 6004                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6005                && code_actions
 6006                    .as_ref()
 6007                    .map_or(true, |actions| actions.is_empty())
 6008                && debug_scenarios.is_empty();
 6009
 6010            editor.update_in(cx, |editor, window, cx| {
 6011                crate::hover_popover::hide_hover(editor, cx);
 6012                let actions = CodeActionContents::new(
 6013                    resolved_tasks,
 6014                    code_actions,
 6015                    debug_scenarios,
 6016                    task_context.unwrap_or_default(),
 6017                );
 6018
 6019                // Don't show the menu if there are no actions available
 6020                if actions.is_empty() {
 6021                    cx.notify();
 6022                    return Task::ready(Ok(()));
 6023                }
 6024
 6025                *editor.context_menu.borrow_mut() =
 6026                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6027                        buffer,
 6028                        actions,
 6029                        selected_item: Default::default(),
 6030                        scroll_handle: UniformListScrollHandle::default(),
 6031                        deployed_from,
 6032                    }));
 6033                cx.notify();
 6034                if spawn_straight_away {
 6035                    if let Some(task) = editor.confirm_code_action(
 6036                        &ConfirmCodeAction { item_ix: Some(0) },
 6037                        window,
 6038                        cx,
 6039                    ) {
 6040                        return task;
 6041                    }
 6042                }
 6043
 6044                Task::ready(Ok(()))
 6045            })
 6046        })
 6047        .detach_and_log_err(cx);
 6048    }
 6049
 6050    fn debug_scenarios(
 6051        &mut self,
 6052        resolved_tasks: &Option<ResolvedTasks>,
 6053        buffer: &Entity<Buffer>,
 6054        cx: &mut App,
 6055    ) -> Task<Vec<task::DebugScenario>> {
 6056        maybe!({
 6057            let project = self.project.as_ref()?;
 6058            let dap_store = project.read(cx).dap_store();
 6059            let mut scenarios = vec![];
 6060            let resolved_tasks = resolved_tasks.as_ref()?;
 6061            let buffer = buffer.read(cx);
 6062            let language = buffer.language()?;
 6063            let file = buffer.file();
 6064            let debug_adapter = language_settings(language.name().into(), file, cx)
 6065                .debuggers
 6066                .first()
 6067                .map(SharedString::from)
 6068                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6069
 6070            dap_store.update(cx, |dap_store, cx| {
 6071                for (_, task) in &resolved_tasks.templates {
 6072                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6073                        task.original_task().clone(),
 6074                        debug_adapter.clone().into(),
 6075                        task.display_label().to_owned().into(),
 6076                        cx,
 6077                    );
 6078                    scenarios.push(maybe_scenario);
 6079                }
 6080            });
 6081            Some(cx.background_spawn(async move {
 6082                let scenarios = futures::future::join_all(scenarios)
 6083                    .await
 6084                    .into_iter()
 6085                    .flatten()
 6086                    .collect::<Vec<_>>();
 6087                scenarios
 6088            }))
 6089        })
 6090        .unwrap_or_else(|| Task::ready(vec![]))
 6091    }
 6092
 6093    fn code_actions(
 6094        &mut self,
 6095        buffer_row: u32,
 6096        window: &mut Window,
 6097        cx: &mut Context<Self>,
 6098    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6099        let mut task = self.code_actions_task.take();
 6100        cx.spawn_in(window, async move |editor, cx| {
 6101            while let Some(prev_task) = task {
 6102                prev_task.await.log_err();
 6103                task = editor
 6104                    .update(cx, |this, _| this.code_actions_task.take())
 6105                    .ok()?;
 6106            }
 6107
 6108            editor
 6109                .update(cx, |editor, cx| {
 6110                    editor
 6111                        .available_code_actions
 6112                        .clone()
 6113                        .and_then(|(location, code_actions)| {
 6114                            let snapshot = location.buffer.read(cx).snapshot();
 6115                            let point_range = location.range.to_point(&snapshot);
 6116                            let point_range = point_range.start.row..=point_range.end.row;
 6117                            if point_range.contains(&buffer_row) {
 6118                                Some(code_actions)
 6119                            } else {
 6120                                None
 6121                            }
 6122                        })
 6123                })
 6124                .ok()
 6125                .flatten()
 6126        })
 6127    }
 6128
 6129    pub fn confirm_code_action(
 6130        &mut self,
 6131        action: &ConfirmCodeAction,
 6132        window: &mut Window,
 6133        cx: &mut Context<Self>,
 6134    ) -> Option<Task<Result<()>>> {
 6135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6136
 6137        let actions_menu =
 6138            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6139                menu
 6140            } else {
 6141                return None;
 6142            };
 6143
 6144        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6145        let action = actions_menu.actions.get(action_ix)?;
 6146        let title = action.label();
 6147        let buffer = actions_menu.buffer;
 6148        let workspace = self.workspace()?;
 6149
 6150        match action {
 6151            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6152                workspace.update(cx, |workspace, cx| {
 6153                    workspace.schedule_resolved_task(
 6154                        task_source_kind,
 6155                        resolved_task,
 6156                        false,
 6157                        window,
 6158                        cx,
 6159                    );
 6160
 6161                    Some(Task::ready(Ok(())))
 6162                })
 6163            }
 6164            CodeActionsItem::CodeAction {
 6165                excerpt_id,
 6166                action,
 6167                provider,
 6168            } => {
 6169                let apply_code_action =
 6170                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6171                let workspace = workspace.downgrade();
 6172                Some(cx.spawn_in(window, async move |editor, cx| {
 6173                    let project_transaction = apply_code_action.await?;
 6174                    Self::open_project_transaction(
 6175                        &editor,
 6176                        workspace,
 6177                        project_transaction,
 6178                        title,
 6179                        cx,
 6180                    )
 6181                    .await
 6182                }))
 6183            }
 6184            CodeActionsItem::DebugScenario(scenario) => {
 6185                let context = actions_menu.actions.context.clone();
 6186
 6187                workspace.update(cx, |workspace, cx| {
 6188                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6189                    workspace.start_debug_session(
 6190                        scenario,
 6191                        context,
 6192                        Some(buffer),
 6193                        None,
 6194                        window,
 6195                        cx,
 6196                    );
 6197                });
 6198                Some(Task::ready(Ok(())))
 6199            }
 6200        }
 6201    }
 6202
 6203    pub async fn open_project_transaction(
 6204        this: &WeakEntity<Editor>,
 6205        workspace: WeakEntity<Workspace>,
 6206        transaction: ProjectTransaction,
 6207        title: String,
 6208        cx: &mut AsyncWindowContext,
 6209    ) -> Result<()> {
 6210        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6211        cx.update(|_, cx| {
 6212            entries.sort_unstable_by_key(|(buffer, _)| {
 6213                buffer.read(cx).file().map(|f| f.path().clone())
 6214            });
 6215        })?;
 6216
 6217        // If the project transaction's edits are all contained within this editor, then
 6218        // avoid opening a new editor to display them.
 6219
 6220        if let Some((buffer, transaction)) = entries.first() {
 6221            if entries.len() == 1 {
 6222                let excerpt = this.update(cx, |editor, cx| {
 6223                    editor
 6224                        .buffer()
 6225                        .read(cx)
 6226                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6227                })?;
 6228                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6229                    if excerpted_buffer == *buffer {
 6230                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6231                            let excerpt_range = excerpt_range.to_offset(buffer);
 6232                            buffer
 6233                                .edited_ranges_for_transaction::<usize>(transaction)
 6234                                .all(|range| {
 6235                                    excerpt_range.start <= range.start
 6236                                        && excerpt_range.end >= range.end
 6237                                })
 6238                        })?;
 6239
 6240                        if all_edits_within_excerpt {
 6241                            return Ok(());
 6242                        }
 6243                    }
 6244                }
 6245            }
 6246        } else {
 6247            return Ok(());
 6248        }
 6249
 6250        let mut ranges_to_highlight = Vec::new();
 6251        let excerpt_buffer = cx.new(|cx| {
 6252            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6253            for (buffer_handle, transaction) in &entries {
 6254                let edited_ranges = buffer_handle
 6255                    .read(cx)
 6256                    .edited_ranges_for_transaction::<Point>(transaction)
 6257                    .collect::<Vec<_>>();
 6258                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6259                    PathKey::for_buffer(buffer_handle, cx),
 6260                    buffer_handle.clone(),
 6261                    edited_ranges,
 6262                    DEFAULT_MULTIBUFFER_CONTEXT,
 6263                    cx,
 6264                );
 6265
 6266                ranges_to_highlight.extend(ranges);
 6267            }
 6268            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6269            multibuffer
 6270        })?;
 6271
 6272        workspace.update_in(cx, |workspace, window, cx| {
 6273            let project = workspace.project().clone();
 6274            let editor =
 6275                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6276            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6277            editor.update(cx, |editor, cx| {
 6278                editor.highlight_background::<Self>(
 6279                    &ranges_to_highlight,
 6280                    |theme| theme.colors().editor_highlighted_line_background,
 6281                    cx,
 6282                );
 6283            });
 6284        })?;
 6285
 6286        Ok(())
 6287    }
 6288
 6289    pub fn clear_code_action_providers(&mut self) {
 6290        self.code_action_providers.clear();
 6291        self.available_code_actions.take();
 6292    }
 6293
 6294    pub fn add_code_action_provider(
 6295        &mut self,
 6296        provider: Rc<dyn CodeActionProvider>,
 6297        window: &mut Window,
 6298        cx: &mut Context<Self>,
 6299    ) {
 6300        if self
 6301            .code_action_providers
 6302            .iter()
 6303            .any(|existing_provider| existing_provider.id() == provider.id())
 6304        {
 6305            return;
 6306        }
 6307
 6308        self.code_action_providers.push(provider);
 6309        self.refresh_code_actions(window, cx);
 6310    }
 6311
 6312    pub fn remove_code_action_provider(
 6313        &mut self,
 6314        id: Arc<str>,
 6315        window: &mut Window,
 6316        cx: &mut Context<Self>,
 6317    ) {
 6318        self.code_action_providers
 6319            .retain(|provider| provider.id() != id);
 6320        self.refresh_code_actions(window, cx);
 6321    }
 6322
 6323    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6324        !self.code_action_providers.is_empty()
 6325            && EditorSettings::get_global(cx).toolbar.code_actions
 6326    }
 6327
 6328    pub fn has_available_code_actions(&self) -> bool {
 6329        self.available_code_actions
 6330            .as_ref()
 6331            .is_some_and(|(_, actions)| !actions.is_empty())
 6332    }
 6333
 6334    fn render_inline_code_actions(
 6335        &self,
 6336        icon_size: ui::IconSize,
 6337        display_row: DisplayRow,
 6338        is_active: bool,
 6339        cx: &mut Context<Self>,
 6340    ) -> AnyElement {
 6341        let show_tooltip = !self.context_menu_visible();
 6342        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6343            .icon_size(icon_size)
 6344            .shape(ui::IconButtonShape::Square)
 6345            .style(ButtonStyle::Transparent)
 6346            .icon_color(ui::Color::Hidden)
 6347            .toggle_state(is_active)
 6348            .when(show_tooltip, |this| {
 6349                this.tooltip({
 6350                    let focus_handle = self.focus_handle.clone();
 6351                    move |window, cx| {
 6352                        Tooltip::for_action_in(
 6353                            "Toggle Code Actions",
 6354                            &ToggleCodeActions {
 6355                                deployed_from: None,
 6356                                quick_launch: false,
 6357                            },
 6358                            &focus_handle,
 6359                            window,
 6360                            cx,
 6361                        )
 6362                    }
 6363                })
 6364            })
 6365            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6366                window.focus(&editor.focus_handle(cx));
 6367                editor.toggle_code_actions(
 6368                    &crate::actions::ToggleCodeActions {
 6369                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6370                            display_row,
 6371                        )),
 6372                        quick_launch: false,
 6373                    },
 6374                    window,
 6375                    cx,
 6376                );
 6377            }))
 6378            .into_any_element()
 6379    }
 6380
 6381    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6382        &self.context_menu
 6383    }
 6384
 6385    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6386        let newest_selection = self.selections.newest_anchor().clone();
 6387        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6388        let buffer = self.buffer.read(cx);
 6389        if newest_selection.head().diff_base_anchor.is_some() {
 6390            return None;
 6391        }
 6392        let (start_buffer, start) =
 6393            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6394        let (end_buffer, end) =
 6395            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6396        if start_buffer != end_buffer {
 6397            return None;
 6398        }
 6399
 6400        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6401            cx.background_executor()
 6402                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6403                .await;
 6404
 6405            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6406                let providers = this.code_action_providers.clone();
 6407                let tasks = this
 6408                    .code_action_providers
 6409                    .iter()
 6410                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6411                    .collect::<Vec<_>>();
 6412                (providers, tasks)
 6413            })?;
 6414
 6415            let mut actions = Vec::new();
 6416            for (provider, provider_actions) in
 6417                providers.into_iter().zip(future::join_all(tasks).await)
 6418            {
 6419                if let Some(provider_actions) = provider_actions.log_err() {
 6420                    actions.extend(provider_actions.into_iter().map(|action| {
 6421                        AvailableCodeAction {
 6422                            excerpt_id: newest_selection.start.excerpt_id,
 6423                            action,
 6424                            provider: provider.clone(),
 6425                        }
 6426                    }));
 6427                }
 6428            }
 6429
 6430            this.update(cx, |this, cx| {
 6431                this.available_code_actions = if actions.is_empty() {
 6432                    None
 6433                } else {
 6434                    Some((
 6435                        Location {
 6436                            buffer: start_buffer,
 6437                            range: start..end,
 6438                        },
 6439                        actions.into(),
 6440                    ))
 6441                };
 6442                cx.notify();
 6443            })
 6444        }));
 6445        None
 6446    }
 6447
 6448    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6449        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6450            self.show_git_blame_inline = false;
 6451
 6452            self.show_git_blame_inline_delay_task =
 6453                Some(cx.spawn_in(window, async move |this, cx| {
 6454                    cx.background_executor().timer(delay).await;
 6455
 6456                    this.update(cx, |this, cx| {
 6457                        this.show_git_blame_inline = true;
 6458                        cx.notify();
 6459                    })
 6460                    .log_err();
 6461                }));
 6462        }
 6463    }
 6464
 6465    fn show_blame_popover(
 6466        &mut self,
 6467        blame_entry: &BlameEntry,
 6468        position: gpui::Point<Pixels>,
 6469        cx: &mut Context<Self>,
 6470    ) {
 6471        if let Some(state) = &mut self.inline_blame_popover {
 6472            state.hide_task.take();
 6473        } else {
 6474            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6475            let blame_entry = blame_entry.clone();
 6476            let show_task = cx.spawn(async move |editor, cx| {
 6477                cx.background_executor()
 6478                    .timer(std::time::Duration::from_millis(delay))
 6479                    .await;
 6480                editor
 6481                    .update(cx, |editor, cx| {
 6482                        editor.inline_blame_popover_show_task.take();
 6483                        let Some(blame) = editor.blame.as_ref() else {
 6484                            return;
 6485                        };
 6486                        let blame = blame.read(cx);
 6487                        let details = blame.details_for_entry(&blame_entry);
 6488                        let markdown = cx.new(|cx| {
 6489                            Markdown::new(
 6490                                details
 6491                                    .as_ref()
 6492                                    .map(|message| message.message.clone())
 6493                                    .unwrap_or_default(),
 6494                                None,
 6495                                None,
 6496                                cx,
 6497                            )
 6498                        });
 6499                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6500                            position,
 6501                            hide_task: None,
 6502                            popover_bounds: None,
 6503                            popover_state: InlineBlamePopoverState {
 6504                                scroll_handle: ScrollHandle::new(),
 6505                                commit_message: details,
 6506                                markdown,
 6507                            },
 6508                        });
 6509                        cx.notify();
 6510                    })
 6511                    .ok();
 6512            });
 6513            self.inline_blame_popover_show_task = Some(show_task);
 6514        }
 6515    }
 6516
 6517    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6518        self.inline_blame_popover_show_task.take();
 6519        if let Some(state) = &mut self.inline_blame_popover {
 6520            let hide_task = cx.spawn(async move |editor, cx| {
 6521                cx.background_executor()
 6522                    .timer(std::time::Duration::from_millis(100))
 6523                    .await;
 6524                editor
 6525                    .update(cx, |editor, cx| {
 6526                        editor.inline_blame_popover.take();
 6527                        cx.notify();
 6528                    })
 6529                    .ok();
 6530            });
 6531            state.hide_task = Some(hide_task);
 6532        }
 6533    }
 6534
 6535    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6536        if self.pending_rename.is_some() {
 6537            return None;
 6538        }
 6539
 6540        let provider = self.semantics_provider.clone()?;
 6541        let buffer = self.buffer.read(cx);
 6542        let newest_selection = self.selections.newest_anchor().clone();
 6543        let cursor_position = newest_selection.head();
 6544        let (cursor_buffer, cursor_buffer_position) =
 6545            buffer.text_anchor_for_position(cursor_position, cx)?;
 6546        let (tail_buffer, tail_buffer_position) =
 6547            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6548        if cursor_buffer != tail_buffer {
 6549            return None;
 6550        }
 6551
 6552        let snapshot = cursor_buffer.read(cx).snapshot();
 6553        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6554        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6555        if start_word_range != end_word_range {
 6556            self.document_highlights_task.take();
 6557            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6558            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6559            return None;
 6560        }
 6561
 6562        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6563        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6564            cx.background_executor()
 6565                .timer(Duration::from_millis(debounce))
 6566                .await;
 6567
 6568            let highlights = if let Some(highlights) = cx
 6569                .update(|cx| {
 6570                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6571                })
 6572                .ok()
 6573                .flatten()
 6574            {
 6575                highlights.await.log_err()
 6576            } else {
 6577                None
 6578            };
 6579
 6580            if let Some(highlights) = highlights {
 6581                this.update(cx, |this, cx| {
 6582                    if this.pending_rename.is_some() {
 6583                        return;
 6584                    }
 6585
 6586                    let buffer_id = cursor_position.buffer_id;
 6587                    let buffer = this.buffer.read(cx);
 6588                    if !buffer
 6589                        .text_anchor_for_position(cursor_position, cx)
 6590                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6591                    {
 6592                        return;
 6593                    }
 6594
 6595                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6596                    let mut write_ranges = Vec::new();
 6597                    let mut read_ranges = Vec::new();
 6598                    for highlight in highlights {
 6599                        for (excerpt_id, excerpt_range) in
 6600                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6601                        {
 6602                            let start = highlight
 6603                                .range
 6604                                .start
 6605                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6606                            let end = highlight
 6607                                .range
 6608                                .end
 6609                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6610                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6611                                continue;
 6612                            }
 6613
 6614                            let range = Anchor {
 6615                                buffer_id,
 6616                                excerpt_id,
 6617                                text_anchor: start,
 6618                                diff_base_anchor: None,
 6619                            }..Anchor {
 6620                                buffer_id,
 6621                                excerpt_id,
 6622                                text_anchor: end,
 6623                                diff_base_anchor: None,
 6624                            };
 6625                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6626                                write_ranges.push(range);
 6627                            } else {
 6628                                read_ranges.push(range);
 6629                            }
 6630                        }
 6631                    }
 6632
 6633                    this.highlight_background::<DocumentHighlightRead>(
 6634                        &read_ranges,
 6635                        |theme| theme.colors().editor_document_highlight_read_background,
 6636                        cx,
 6637                    );
 6638                    this.highlight_background::<DocumentHighlightWrite>(
 6639                        &write_ranges,
 6640                        |theme| theme.colors().editor_document_highlight_write_background,
 6641                        cx,
 6642                    );
 6643                    cx.notify();
 6644                })
 6645                .log_err();
 6646            }
 6647        }));
 6648        None
 6649    }
 6650
 6651    fn prepare_highlight_query_from_selection(
 6652        &mut self,
 6653        cx: &mut Context<Editor>,
 6654    ) -> Option<(String, Range<Anchor>)> {
 6655        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6656            return None;
 6657        }
 6658        if !EditorSettings::get_global(cx).selection_highlight {
 6659            return None;
 6660        }
 6661        if self.selections.count() != 1 || self.selections.line_mode {
 6662            return None;
 6663        }
 6664        let selection = self.selections.newest::<Point>(cx);
 6665        if selection.is_empty() || selection.start.row != selection.end.row {
 6666            return None;
 6667        }
 6668        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6669        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6670        let query = multi_buffer_snapshot
 6671            .text_for_range(selection_anchor_range.clone())
 6672            .collect::<String>();
 6673        if query.trim().is_empty() {
 6674            return None;
 6675        }
 6676        Some((query, selection_anchor_range))
 6677    }
 6678
 6679    fn update_selection_occurrence_highlights(
 6680        &mut self,
 6681        query_text: String,
 6682        query_range: Range<Anchor>,
 6683        multi_buffer_range_to_query: Range<Point>,
 6684        use_debounce: bool,
 6685        window: &mut Window,
 6686        cx: &mut Context<Editor>,
 6687    ) -> Task<()> {
 6688        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6689        cx.spawn_in(window, async move |editor, cx| {
 6690            if use_debounce {
 6691                cx.background_executor()
 6692                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6693                    .await;
 6694            }
 6695            let match_task = cx.background_spawn(async move {
 6696                let buffer_ranges = multi_buffer_snapshot
 6697                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6698                    .into_iter()
 6699                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6700                let mut match_ranges = Vec::new();
 6701                let Ok(regex) = project::search::SearchQuery::text(
 6702                    query_text.clone(),
 6703                    false,
 6704                    false,
 6705                    false,
 6706                    Default::default(),
 6707                    Default::default(),
 6708                    false,
 6709                    None,
 6710                ) else {
 6711                    return Vec::default();
 6712                };
 6713                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6714                    match_ranges.extend(
 6715                        regex
 6716                            .search(&buffer_snapshot, Some(search_range.clone()))
 6717                            .await
 6718                            .into_iter()
 6719                            .filter_map(|match_range| {
 6720                                let match_start = buffer_snapshot
 6721                                    .anchor_after(search_range.start + match_range.start);
 6722                                let match_end = buffer_snapshot
 6723                                    .anchor_before(search_range.start + match_range.end);
 6724                                let match_anchor_range = Anchor::range_in_buffer(
 6725                                    excerpt_id,
 6726                                    buffer_snapshot.remote_id(),
 6727                                    match_start..match_end,
 6728                                );
 6729                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6730                            }),
 6731                    );
 6732                }
 6733                match_ranges
 6734            });
 6735            let match_ranges = match_task.await;
 6736            editor
 6737                .update_in(cx, |editor, _, cx| {
 6738                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6739                    if !match_ranges.is_empty() {
 6740                        editor.highlight_background::<SelectedTextHighlight>(
 6741                            &match_ranges,
 6742                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6743                            cx,
 6744                        )
 6745                    }
 6746                })
 6747                .log_err();
 6748        })
 6749    }
 6750
 6751    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6752        struct NewlineFold;
 6753        let type_id = std::any::TypeId::of::<NewlineFold>();
 6754        if !self.mode.is_single_line() {
 6755            return;
 6756        }
 6757        let snapshot = self.snapshot(window, cx);
 6758        if snapshot.buffer_snapshot.max_point().row == 0 {
 6759            return;
 6760        }
 6761        let task = cx.background_spawn(async move {
 6762            let new_newlines = snapshot
 6763                .buffer_chars_at(0)
 6764                .filter_map(|(c, i)| {
 6765                    if c == '\n' {
 6766                        Some(
 6767                            snapshot.buffer_snapshot.anchor_after(i)
 6768                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6769                        )
 6770                    } else {
 6771                        None
 6772                    }
 6773                })
 6774                .collect::<Vec<_>>();
 6775            let existing_newlines = snapshot
 6776                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6777                .filter_map(|fold| {
 6778                    if fold.placeholder.type_tag == Some(type_id) {
 6779                        Some(fold.range.start..fold.range.end)
 6780                    } else {
 6781                        None
 6782                    }
 6783                })
 6784                .collect::<Vec<_>>();
 6785
 6786            (new_newlines, existing_newlines)
 6787        });
 6788        self.folding_newlines = cx.spawn(async move |this, cx| {
 6789            let (new_newlines, existing_newlines) = task.await;
 6790            if new_newlines == existing_newlines {
 6791                return;
 6792            }
 6793            let placeholder = FoldPlaceholder {
 6794                render: Arc::new(move |_, _, cx| {
 6795                    div()
 6796                        .bg(cx.theme().status().hint_background)
 6797                        .border_b_1()
 6798                        .size_full()
 6799                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6800                        .border_color(cx.theme().status().hint)
 6801                        .child("\\n")
 6802                        .into_any()
 6803                }),
 6804                constrain_width: false,
 6805                merge_adjacent: false,
 6806                type_tag: Some(type_id),
 6807            };
 6808            let creases = new_newlines
 6809                .into_iter()
 6810                .map(|range| Crease::simple(range, placeholder.clone()))
 6811                .collect();
 6812            this.update(cx, |this, cx| {
 6813                this.display_map.update(cx, |display_map, cx| {
 6814                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6815                    display_map.fold(creases, cx);
 6816                });
 6817            })
 6818            .ok();
 6819        });
 6820    }
 6821
 6822    fn refresh_selected_text_highlights(
 6823        &mut self,
 6824        on_buffer_edit: bool,
 6825        window: &mut Window,
 6826        cx: &mut Context<Editor>,
 6827    ) {
 6828        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6829        else {
 6830            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6831            self.quick_selection_highlight_task.take();
 6832            self.debounced_selection_highlight_task.take();
 6833            return;
 6834        };
 6835        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6836        if on_buffer_edit
 6837            || self
 6838                .quick_selection_highlight_task
 6839                .as_ref()
 6840                .map_or(true, |(prev_anchor_range, _)| {
 6841                    prev_anchor_range != &query_range
 6842                })
 6843        {
 6844            let multi_buffer_visible_start = self
 6845                .scroll_manager
 6846                .anchor()
 6847                .anchor
 6848                .to_point(&multi_buffer_snapshot);
 6849            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6850                multi_buffer_visible_start
 6851                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6852                Bias::Left,
 6853            );
 6854            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6855            self.quick_selection_highlight_task = Some((
 6856                query_range.clone(),
 6857                self.update_selection_occurrence_highlights(
 6858                    query_text.clone(),
 6859                    query_range.clone(),
 6860                    multi_buffer_visible_range,
 6861                    false,
 6862                    window,
 6863                    cx,
 6864                ),
 6865            ));
 6866        }
 6867        if on_buffer_edit
 6868            || self
 6869                .debounced_selection_highlight_task
 6870                .as_ref()
 6871                .map_or(true, |(prev_anchor_range, _)| {
 6872                    prev_anchor_range != &query_range
 6873                })
 6874        {
 6875            let multi_buffer_start = multi_buffer_snapshot
 6876                .anchor_before(0)
 6877                .to_point(&multi_buffer_snapshot);
 6878            let multi_buffer_end = multi_buffer_snapshot
 6879                .anchor_after(multi_buffer_snapshot.len())
 6880                .to_point(&multi_buffer_snapshot);
 6881            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6882            self.debounced_selection_highlight_task = Some((
 6883                query_range.clone(),
 6884                self.update_selection_occurrence_highlights(
 6885                    query_text,
 6886                    query_range,
 6887                    multi_buffer_full_range,
 6888                    true,
 6889                    window,
 6890                    cx,
 6891                ),
 6892            ));
 6893        }
 6894    }
 6895
 6896    pub fn refresh_inline_completion(
 6897        &mut self,
 6898        debounce: bool,
 6899        user_requested: bool,
 6900        window: &mut Window,
 6901        cx: &mut Context<Self>,
 6902    ) -> Option<()> {
 6903        let provider = self.edit_prediction_provider()?;
 6904        let cursor = self.selections.newest_anchor().head();
 6905        let (buffer, cursor_buffer_position) =
 6906            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6907
 6908        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6909            self.discard_inline_completion(false, cx);
 6910            return None;
 6911        }
 6912
 6913        if !user_requested
 6914            && (!self.should_show_edit_predictions()
 6915                || !self.is_focused(window)
 6916                || buffer.read(cx).is_empty())
 6917        {
 6918            self.discard_inline_completion(false, cx);
 6919            return None;
 6920        }
 6921
 6922        self.update_visible_inline_completion(window, cx);
 6923        provider.refresh(
 6924            self.project.clone(),
 6925            buffer,
 6926            cursor_buffer_position,
 6927            debounce,
 6928            cx,
 6929        );
 6930        Some(())
 6931    }
 6932
 6933    fn show_edit_predictions_in_menu(&self) -> bool {
 6934        match self.edit_prediction_settings {
 6935            EditPredictionSettings::Disabled => false,
 6936            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6937        }
 6938    }
 6939
 6940    pub fn edit_predictions_enabled(&self) -> bool {
 6941        match self.edit_prediction_settings {
 6942            EditPredictionSettings::Disabled => false,
 6943            EditPredictionSettings::Enabled { .. } => true,
 6944        }
 6945    }
 6946
 6947    fn edit_prediction_requires_modifier(&self) -> bool {
 6948        match self.edit_prediction_settings {
 6949            EditPredictionSettings::Disabled => false,
 6950            EditPredictionSettings::Enabled {
 6951                preview_requires_modifier,
 6952                ..
 6953            } => preview_requires_modifier,
 6954        }
 6955    }
 6956
 6957    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6958        if self.edit_prediction_provider.is_none() {
 6959            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6960        } else {
 6961            let selection = self.selections.newest_anchor();
 6962            let cursor = selection.head();
 6963
 6964            if let Some((buffer, cursor_buffer_position)) =
 6965                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6966            {
 6967                self.edit_prediction_settings =
 6968                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6969            }
 6970        }
 6971    }
 6972
 6973    fn edit_prediction_settings_at_position(
 6974        &self,
 6975        buffer: &Entity<Buffer>,
 6976        buffer_position: language::Anchor,
 6977        cx: &App,
 6978    ) -> EditPredictionSettings {
 6979        if !self.mode.is_full()
 6980            || !self.show_inline_completions_override.unwrap_or(true)
 6981            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6982        {
 6983            return EditPredictionSettings::Disabled;
 6984        }
 6985
 6986        let buffer = buffer.read(cx);
 6987
 6988        let file = buffer.file();
 6989
 6990        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6991            return EditPredictionSettings::Disabled;
 6992        };
 6993
 6994        let by_provider = matches!(
 6995            self.menu_inline_completions_policy,
 6996            MenuInlineCompletionsPolicy::ByProvider
 6997        );
 6998
 6999        let show_in_menu = by_provider
 7000            && self
 7001                .edit_prediction_provider
 7002                .as_ref()
 7003                .map_or(false, |provider| {
 7004                    provider.provider.show_completions_in_menu()
 7005                });
 7006
 7007        let preview_requires_modifier =
 7008            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7009
 7010        EditPredictionSettings::Enabled {
 7011            show_in_menu,
 7012            preview_requires_modifier,
 7013        }
 7014    }
 7015
 7016    fn should_show_edit_predictions(&self) -> bool {
 7017        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7018    }
 7019
 7020    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7021        matches!(
 7022            self.edit_prediction_preview,
 7023            EditPredictionPreview::Active { .. }
 7024        )
 7025    }
 7026
 7027    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7028        let cursor = self.selections.newest_anchor().head();
 7029        if let Some((buffer, cursor_position)) =
 7030            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7031        {
 7032            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7033        } else {
 7034            false
 7035        }
 7036    }
 7037
 7038    pub fn supports_minimap(&self, cx: &App) -> bool {
 7039        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7040    }
 7041
 7042    fn edit_predictions_enabled_in_buffer(
 7043        &self,
 7044        buffer: &Entity<Buffer>,
 7045        buffer_position: language::Anchor,
 7046        cx: &App,
 7047    ) -> bool {
 7048        maybe!({
 7049            if self.read_only(cx) {
 7050                return Some(false);
 7051            }
 7052            let provider = self.edit_prediction_provider()?;
 7053            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7054                return Some(false);
 7055            }
 7056            let buffer = buffer.read(cx);
 7057            let Some(file) = buffer.file() else {
 7058                return Some(true);
 7059            };
 7060            let settings = all_language_settings(Some(file), cx);
 7061            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7062        })
 7063        .unwrap_or(false)
 7064    }
 7065
 7066    fn cycle_inline_completion(
 7067        &mut self,
 7068        direction: Direction,
 7069        window: &mut Window,
 7070        cx: &mut Context<Self>,
 7071    ) -> Option<()> {
 7072        let provider = self.edit_prediction_provider()?;
 7073        let cursor = self.selections.newest_anchor().head();
 7074        let (buffer, cursor_buffer_position) =
 7075            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7076        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7077            return None;
 7078        }
 7079
 7080        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7081        self.update_visible_inline_completion(window, cx);
 7082
 7083        Some(())
 7084    }
 7085
 7086    pub fn show_inline_completion(
 7087        &mut self,
 7088        _: &ShowEditPrediction,
 7089        window: &mut Window,
 7090        cx: &mut Context<Self>,
 7091    ) {
 7092        if !self.has_active_inline_completion() {
 7093            self.refresh_inline_completion(false, true, window, cx);
 7094            return;
 7095        }
 7096
 7097        self.update_visible_inline_completion(window, cx);
 7098    }
 7099
 7100    pub fn display_cursor_names(
 7101        &mut self,
 7102        _: &DisplayCursorNames,
 7103        window: &mut Window,
 7104        cx: &mut Context<Self>,
 7105    ) {
 7106        self.show_cursor_names(window, cx);
 7107    }
 7108
 7109    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7110        self.show_cursor_names = true;
 7111        cx.notify();
 7112        cx.spawn_in(window, async move |this, cx| {
 7113            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7114            this.update(cx, |this, cx| {
 7115                this.show_cursor_names = false;
 7116                cx.notify()
 7117            })
 7118            .ok()
 7119        })
 7120        .detach();
 7121    }
 7122
 7123    pub fn next_edit_prediction(
 7124        &mut self,
 7125        _: &NextEditPrediction,
 7126        window: &mut Window,
 7127        cx: &mut Context<Self>,
 7128    ) {
 7129        if self.has_active_inline_completion() {
 7130            self.cycle_inline_completion(Direction::Next, window, cx);
 7131        } else {
 7132            let is_copilot_disabled = self
 7133                .refresh_inline_completion(false, true, window, cx)
 7134                .is_none();
 7135            if is_copilot_disabled {
 7136                cx.propagate();
 7137            }
 7138        }
 7139    }
 7140
 7141    pub fn previous_edit_prediction(
 7142        &mut self,
 7143        _: &PreviousEditPrediction,
 7144        window: &mut Window,
 7145        cx: &mut Context<Self>,
 7146    ) {
 7147        if self.has_active_inline_completion() {
 7148            self.cycle_inline_completion(Direction::Prev, window, cx);
 7149        } else {
 7150            let is_copilot_disabled = self
 7151                .refresh_inline_completion(false, true, window, cx)
 7152                .is_none();
 7153            if is_copilot_disabled {
 7154                cx.propagate();
 7155            }
 7156        }
 7157    }
 7158
 7159    pub fn accept_edit_prediction(
 7160        &mut self,
 7161        _: &AcceptEditPrediction,
 7162        window: &mut Window,
 7163        cx: &mut Context<Self>,
 7164    ) {
 7165        if self.show_edit_predictions_in_menu() {
 7166            self.hide_context_menu(window, cx);
 7167        }
 7168
 7169        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7170            return;
 7171        };
 7172
 7173        self.report_inline_completion_event(
 7174            active_inline_completion.completion_id.clone(),
 7175            true,
 7176            cx,
 7177        );
 7178
 7179        match &active_inline_completion.completion {
 7180            InlineCompletion::Move { target, .. } => {
 7181                let target = *target;
 7182
 7183                if let Some(position_map) = &self.last_position_map {
 7184                    if position_map
 7185                        .visible_row_range
 7186                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7187                        || !self.edit_prediction_requires_modifier()
 7188                    {
 7189                        self.unfold_ranges(&[target..target], true, false, cx);
 7190                        // Note that this is also done in vim's handler of the Tab action.
 7191                        self.change_selections(
 7192                            SelectionEffects::scroll(Autoscroll::newest()),
 7193                            window,
 7194                            cx,
 7195                            |selections| {
 7196                                selections.select_anchor_ranges([target..target]);
 7197                            },
 7198                        );
 7199                        self.clear_row_highlights::<EditPredictionPreview>();
 7200
 7201                        self.edit_prediction_preview
 7202                            .set_previous_scroll_position(None);
 7203                    } else {
 7204                        self.edit_prediction_preview
 7205                            .set_previous_scroll_position(Some(
 7206                                position_map.snapshot.scroll_anchor,
 7207                            ));
 7208
 7209                        self.highlight_rows::<EditPredictionPreview>(
 7210                            target..target,
 7211                            cx.theme().colors().editor_highlighted_line_background,
 7212                            RowHighlightOptions {
 7213                                autoscroll: true,
 7214                                ..Default::default()
 7215                            },
 7216                            cx,
 7217                        );
 7218                        self.request_autoscroll(Autoscroll::fit(), cx);
 7219                    }
 7220                }
 7221            }
 7222            InlineCompletion::Edit { edits, .. } => {
 7223                if let Some(provider) = self.edit_prediction_provider() {
 7224                    provider.accept(cx);
 7225                }
 7226
 7227                // Store the transaction ID and selections before applying the edit
 7228                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7229
 7230                let snapshot = self.buffer.read(cx).snapshot(cx);
 7231                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7232
 7233                self.buffer.update(cx, |buffer, cx| {
 7234                    buffer.edit(edits.iter().cloned(), None, cx)
 7235                });
 7236
 7237                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7238                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7239                });
 7240
 7241                let selections = self.selections.disjoint_anchors();
 7242                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7243                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7244                    if has_new_transaction {
 7245                        self.selection_history
 7246                            .insert_transaction(transaction_id_now, selections);
 7247                    }
 7248                }
 7249
 7250                self.update_visible_inline_completion(window, cx);
 7251                if self.active_inline_completion.is_none() {
 7252                    self.refresh_inline_completion(true, true, window, cx);
 7253                }
 7254
 7255                cx.notify();
 7256            }
 7257        }
 7258
 7259        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7260    }
 7261
 7262    pub fn accept_partial_inline_completion(
 7263        &mut self,
 7264        _: &AcceptPartialEditPrediction,
 7265        window: &mut Window,
 7266        cx: &mut Context<Self>,
 7267    ) {
 7268        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7269            return;
 7270        };
 7271        if self.selections.count() != 1 {
 7272            return;
 7273        }
 7274
 7275        self.report_inline_completion_event(
 7276            active_inline_completion.completion_id.clone(),
 7277            true,
 7278            cx,
 7279        );
 7280
 7281        match &active_inline_completion.completion {
 7282            InlineCompletion::Move { target, .. } => {
 7283                let target = *target;
 7284                self.change_selections(
 7285                    SelectionEffects::scroll(Autoscroll::newest()),
 7286                    window,
 7287                    cx,
 7288                    |selections| {
 7289                        selections.select_anchor_ranges([target..target]);
 7290                    },
 7291                );
 7292            }
 7293            InlineCompletion::Edit { edits, .. } => {
 7294                // Find an insertion that starts at the cursor position.
 7295                let snapshot = self.buffer.read(cx).snapshot(cx);
 7296                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7297                let insertion = edits.iter().find_map(|(range, text)| {
 7298                    let range = range.to_offset(&snapshot);
 7299                    if range.is_empty() && range.start == cursor_offset {
 7300                        Some(text)
 7301                    } else {
 7302                        None
 7303                    }
 7304                });
 7305
 7306                if let Some(text) = insertion {
 7307                    let mut partial_completion = text
 7308                        .chars()
 7309                        .by_ref()
 7310                        .take_while(|c| c.is_alphabetic())
 7311                        .collect::<String>();
 7312                    if partial_completion.is_empty() {
 7313                        partial_completion = text
 7314                            .chars()
 7315                            .by_ref()
 7316                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7317                            .collect::<String>();
 7318                    }
 7319
 7320                    cx.emit(EditorEvent::InputHandled {
 7321                        utf16_range_to_replace: None,
 7322                        text: partial_completion.clone().into(),
 7323                    });
 7324
 7325                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7326
 7327                    self.refresh_inline_completion(true, true, window, cx);
 7328                    cx.notify();
 7329                } else {
 7330                    self.accept_edit_prediction(&Default::default(), window, cx);
 7331                }
 7332            }
 7333        }
 7334    }
 7335
 7336    fn discard_inline_completion(
 7337        &mut self,
 7338        should_report_inline_completion_event: bool,
 7339        cx: &mut Context<Self>,
 7340    ) -> bool {
 7341        if should_report_inline_completion_event {
 7342            let completion_id = self
 7343                .active_inline_completion
 7344                .as_ref()
 7345                .and_then(|active_completion| active_completion.completion_id.clone());
 7346
 7347            self.report_inline_completion_event(completion_id, false, cx);
 7348        }
 7349
 7350        if let Some(provider) = self.edit_prediction_provider() {
 7351            provider.discard(cx);
 7352        }
 7353
 7354        self.take_active_inline_completion(cx)
 7355    }
 7356
 7357    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7358        let Some(provider) = self.edit_prediction_provider() else {
 7359            return;
 7360        };
 7361
 7362        let Some((_, buffer, _)) = self
 7363            .buffer
 7364            .read(cx)
 7365            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7366        else {
 7367            return;
 7368        };
 7369
 7370        let extension = buffer
 7371            .read(cx)
 7372            .file()
 7373            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7374
 7375        let event_type = match accepted {
 7376            true => "Edit Prediction Accepted",
 7377            false => "Edit Prediction Discarded",
 7378        };
 7379        telemetry::event!(
 7380            event_type,
 7381            provider = provider.name(),
 7382            prediction_id = id,
 7383            suggestion_accepted = accepted,
 7384            file_extension = extension,
 7385        );
 7386    }
 7387
 7388    pub fn has_active_inline_completion(&self) -> bool {
 7389        self.active_inline_completion.is_some()
 7390    }
 7391
 7392    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7393        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7394            return false;
 7395        };
 7396
 7397        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7398        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7399        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7400        true
 7401    }
 7402
 7403    /// Returns true when we're displaying the edit prediction popover below the cursor
 7404    /// like we are not previewing and the LSP autocomplete menu is visible
 7405    /// or we are in `when_holding_modifier` mode.
 7406    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7407        if self.edit_prediction_preview_is_active()
 7408            || !self.show_edit_predictions_in_menu()
 7409            || !self.edit_predictions_enabled()
 7410        {
 7411            return false;
 7412        }
 7413
 7414        if self.has_visible_completions_menu() {
 7415            return true;
 7416        }
 7417
 7418        has_completion && self.edit_prediction_requires_modifier()
 7419    }
 7420
 7421    fn handle_modifiers_changed(
 7422        &mut self,
 7423        modifiers: Modifiers,
 7424        position_map: &PositionMap,
 7425        window: &mut Window,
 7426        cx: &mut Context<Self>,
 7427    ) {
 7428        if self.show_edit_predictions_in_menu() {
 7429            self.update_edit_prediction_preview(&modifiers, window, cx);
 7430        }
 7431
 7432        self.update_selection_mode(&modifiers, position_map, window, cx);
 7433
 7434        let mouse_position = window.mouse_position();
 7435        if !position_map.text_hitbox.is_hovered(window) {
 7436            return;
 7437        }
 7438
 7439        self.update_hovered_link(
 7440            position_map.point_for_position(mouse_position),
 7441            &position_map.snapshot,
 7442            modifiers,
 7443            window,
 7444            cx,
 7445        )
 7446    }
 7447
 7448    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7449        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7450        if invert {
 7451            match multi_cursor_setting {
 7452                MultiCursorModifier::Alt => modifiers.alt,
 7453                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7454            }
 7455        } else {
 7456            match multi_cursor_setting {
 7457                MultiCursorModifier::Alt => modifiers.secondary(),
 7458                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7459            }
 7460        }
 7461    }
 7462
 7463    fn columnar_selection_mode(
 7464        modifiers: &Modifiers,
 7465        cx: &mut Context<Self>,
 7466    ) -> Option<ColumnarMode> {
 7467        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7468            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7469                Some(ColumnarMode::FromMouse)
 7470            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7471                Some(ColumnarMode::FromSelection)
 7472            } else {
 7473                None
 7474            }
 7475        } else {
 7476            None
 7477        }
 7478    }
 7479
 7480    fn update_selection_mode(
 7481        &mut self,
 7482        modifiers: &Modifiers,
 7483        position_map: &PositionMap,
 7484        window: &mut Window,
 7485        cx: &mut Context<Self>,
 7486    ) {
 7487        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7488            return;
 7489        };
 7490        if self.selections.pending.is_none() {
 7491            return;
 7492        }
 7493
 7494        let mouse_position = window.mouse_position();
 7495        let point_for_position = position_map.point_for_position(mouse_position);
 7496        let position = point_for_position.previous_valid;
 7497
 7498        self.select(
 7499            SelectPhase::BeginColumnar {
 7500                position,
 7501                reset: false,
 7502                mode,
 7503                goal_column: point_for_position.exact_unclipped.column(),
 7504            },
 7505            window,
 7506            cx,
 7507        );
 7508    }
 7509
 7510    fn update_edit_prediction_preview(
 7511        &mut self,
 7512        modifiers: &Modifiers,
 7513        window: &mut Window,
 7514        cx: &mut Context<Self>,
 7515    ) {
 7516        let mut modifiers_held = false;
 7517        if let Some(accept_keystroke) = self
 7518            .accept_edit_prediction_keybind(false, window, cx)
 7519            .keystroke()
 7520        {
 7521            modifiers_held = modifiers_held
 7522                || (&accept_keystroke.modifiers == modifiers
 7523                    && accept_keystroke.modifiers.modified());
 7524        };
 7525        if let Some(accept_partial_keystroke) = self
 7526            .accept_edit_prediction_keybind(true, window, cx)
 7527            .keystroke()
 7528        {
 7529            modifiers_held = modifiers_held
 7530                || (&accept_partial_keystroke.modifiers == modifiers
 7531                    && accept_partial_keystroke.modifiers.modified());
 7532        }
 7533
 7534        if modifiers_held {
 7535            if matches!(
 7536                self.edit_prediction_preview,
 7537                EditPredictionPreview::Inactive { .. }
 7538            ) {
 7539                self.edit_prediction_preview = EditPredictionPreview::Active {
 7540                    previous_scroll_position: None,
 7541                    since: Instant::now(),
 7542                };
 7543
 7544                self.update_visible_inline_completion(window, cx);
 7545                cx.notify();
 7546            }
 7547        } else if let EditPredictionPreview::Active {
 7548            previous_scroll_position,
 7549            since,
 7550        } = self.edit_prediction_preview
 7551        {
 7552            if let (Some(previous_scroll_position), Some(position_map)) =
 7553                (previous_scroll_position, self.last_position_map.as_ref())
 7554            {
 7555                self.set_scroll_position(
 7556                    previous_scroll_position
 7557                        .scroll_position(&position_map.snapshot.display_snapshot),
 7558                    window,
 7559                    cx,
 7560                );
 7561            }
 7562
 7563            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7564                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7565            };
 7566            self.clear_row_highlights::<EditPredictionPreview>();
 7567            self.update_visible_inline_completion(window, cx);
 7568            cx.notify();
 7569        }
 7570    }
 7571
 7572    fn update_visible_inline_completion(
 7573        &mut self,
 7574        _window: &mut Window,
 7575        cx: &mut Context<Self>,
 7576    ) -> Option<()> {
 7577        let selection = self.selections.newest_anchor();
 7578        let cursor = selection.head();
 7579        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7580        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7581        let excerpt_id = cursor.excerpt_id;
 7582
 7583        let show_in_menu = self.show_edit_predictions_in_menu();
 7584        let completions_menu_has_precedence = !show_in_menu
 7585            && (self.context_menu.borrow().is_some()
 7586                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7587
 7588        if completions_menu_has_precedence
 7589            || !offset_selection.is_empty()
 7590            || self
 7591                .active_inline_completion
 7592                .as_ref()
 7593                .map_or(false, |completion| {
 7594                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7595                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7596                    !invalidation_range.contains(&offset_selection.head())
 7597                })
 7598        {
 7599            self.discard_inline_completion(false, cx);
 7600            return None;
 7601        }
 7602
 7603        self.take_active_inline_completion(cx);
 7604        let Some(provider) = self.edit_prediction_provider() else {
 7605            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7606            return None;
 7607        };
 7608
 7609        let (buffer, cursor_buffer_position) =
 7610            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7611
 7612        self.edit_prediction_settings =
 7613            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7614
 7615        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7616
 7617        if self.edit_prediction_indent_conflict {
 7618            let cursor_point = cursor.to_point(&multibuffer);
 7619
 7620            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7621
 7622            if let Some((_, indent)) = indents.iter().next() {
 7623                if indent.len == cursor_point.column {
 7624                    self.edit_prediction_indent_conflict = false;
 7625                }
 7626            }
 7627        }
 7628
 7629        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7630        let edits = inline_completion
 7631            .edits
 7632            .into_iter()
 7633            .flat_map(|(range, new_text)| {
 7634                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7635                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7636                Some((start..end, new_text))
 7637            })
 7638            .collect::<Vec<_>>();
 7639        if edits.is_empty() {
 7640            return None;
 7641        }
 7642
 7643        let first_edit_start = edits.first().unwrap().0.start;
 7644        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7645        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7646
 7647        let last_edit_end = edits.last().unwrap().0.end;
 7648        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7649        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7650
 7651        let cursor_row = cursor.to_point(&multibuffer).row;
 7652
 7653        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7654
 7655        let mut inlay_ids = Vec::new();
 7656        let invalidation_row_range;
 7657        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7658            Some(cursor_row..edit_end_row)
 7659        } else if cursor_row > edit_end_row {
 7660            Some(edit_start_row..cursor_row)
 7661        } else {
 7662            None
 7663        };
 7664        let is_move =
 7665            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7666        let completion = if is_move {
 7667            invalidation_row_range =
 7668                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7669            let target = first_edit_start;
 7670            InlineCompletion::Move { target, snapshot }
 7671        } else {
 7672            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7673                && !self.inline_completions_hidden_for_vim_mode;
 7674
 7675            if show_completions_in_buffer {
 7676                if edits
 7677                    .iter()
 7678                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7679                {
 7680                    let mut inlays = Vec::new();
 7681                    for (range, new_text) in &edits {
 7682                        let inlay = Inlay::inline_completion(
 7683                            post_inc(&mut self.next_inlay_id),
 7684                            range.start,
 7685                            new_text.as_str(),
 7686                        );
 7687                        inlay_ids.push(inlay.id);
 7688                        inlays.push(inlay);
 7689                    }
 7690
 7691                    self.splice_inlays(&[], inlays, cx);
 7692                } else {
 7693                    let background_color = cx.theme().status().deleted_background;
 7694                    self.highlight_text::<InlineCompletionHighlight>(
 7695                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7696                        HighlightStyle {
 7697                            background_color: Some(background_color),
 7698                            ..Default::default()
 7699                        },
 7700                        cx,
 7701                    );
 7702                }
 7703            }
 7704
 7705            invalidation_row_range = edit_start_row..edit_end_row;
 7706
 7707            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7708                if provider.show_tab_accept_marker() {
 7709                    EditDisplayMode::TabAccept
 7710                } else {
 7711                    EditDisplayMode::Inline
 7712                }
 7713            } else {
 7714                EditDisplayMode::DiffPopover
 7715            };
 7716
 7717            InlineCompletion::Edit {
 7718                edits,
 7719                edit_preview: inline_completion.edit_preview,
 7720                display_mode,
 7721                snapshot,
 7722            }
 7723        };
 7724
 7725        let invalidation_range = multibuffer
 7726            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7727            ..multibuffer.anchor_after(Point::new(
 7728                invalidation_row_range.end,
 7729                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7730            ));
 7731
 7732        self.stale_inline_completion_in_menu = None;
 7733        self.active_inline_completion = Some(InlineCompletionState {
 7734            inlay_ids,
 7735            completion,
 7736            completion_id: inline_completion.id,
 7737            invalidation_range,
 7738        });
 7739
 7740        cx.notify();
 7741
 7742        Some(())
 7743    }
 7744
 7745    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7746        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7747    }
 7748
 7749    fn clear_tasks(&mut self) {
 7750        self.tasks.clear()
 7751    }
 7752
 7753    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7754        if self.tasks.insert(key, value).is_some() {
 7755            // This case should hopefully be rare, but just in case...
 7756            log::error!(
 7757                "multiple different run targets found on a single line, only the last target will be rendered"
 7758            )
 7759        }
 7760    }
 7761
 7762    /// Get all display points of breakpoints that will be rendered within editor
 7763    ///
 7764    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7765    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7766    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7767    fn active_breakpoints(
 7768        &self,
 7769        range: Range<DisplayRow>,
 7770        window: &mut Window,
 7771        cx: &mut Context<Self>,
 7772    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7773        let mut breakpoint_display_points = HashMap::default();
 7774
 7775        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7776            return breakpoint_display_points;
 7777        };
 7778
 7779        let snapshot = self.snapshot(window, cx);
 7780
 7781        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7782        let Some(project) = self.project.as_ref() else {
 7783            return breakpoint_display_points;
 7784        };
 7785
 7786        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7787            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7788
 7789        for (buffer_snapshot, range, excerpt_id) in
 7790            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7791        {
 7792            let Some(buffer) = project
 7793                .read(cx)
 7794                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7795            else {
 7796                continue;
 7797            };
 7798            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7799                &buffer,
 7800                Some(
 7801                    buffer_snapshot.anchor_before(range.start)
 7802                        ..buffer_snapshot.anchor_after(range.end),
 7803                ),
 7804                buffer_snapshot,
 7805                cx,
 7806            );
 7807            for (breakpoint, state) in breakpoints {
 7808                let multi_buffer_anchor =
 7809                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7810                let position = multi_buffer_anchor
 7811                    .to_point(&multi_buffer_snapshot)
 7812                    .to_display_point(&snapshot);
 7813
 7814                breakpoint_display_points.insert(
 7815                    position.row(),
 7816                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7817                );
 7818            }
 7819        }
 7820
 7821        breakpoint_display_points
 7822    }
 7823
 7824    fn breakpoint_context_menu(
 7825        &self,
 7826        anchor: Anchor,
 7827        window: &mut Window,
 7828        cx: &mut Context<Self>,
 7829    ) -> Entity<ui::ContextMenu> {
 7830        let weak_editor = cx.weak_entity();
 7831        let focus_handle = self.focus_handle(cx);
 7832
 7833        let row = self
 7834            .buffer
 7835            .read(cx)
 7836            .snapshot(cx)
 7837            .summary_for_anchor::<Point>(&anchor)
 7838            .row;
 7839
 7840        let breakpoint = self
 7841            .breakpoint_at_row(row, window, cx)
 7842            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7843
 7844        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7845            "Edit Log Breakpoint"
 7846        } else {
 7847            "Set Log Breakpoint"
 7848        };
 7849
 7850        let condition_breakpoint_msg = if breakpoint
 7851            .as_ref()
 7852            .is_some_and(|bp| bp.1.condition.is_some())
 7853        {
 7854            "Edit Condition Breakpoint"
 7855        } else {
 7856            "Set Condition Breakpoint"
 7857        };
 7858
 7859        let hit_condition_breakpoint_msg = if breakpoint
 7860            .as_ref()
 7861            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7862        {
 7863            "Edit Hit Condition Breakpoint"
 7864        } else {
 7865            "Set Hit Condition Breakpoint"
 7866        };
 7867
 7868        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7869            "Unset Breakpoint"
 7870        } else {
 7871            "Set Breakpoint"
 7872        };
 7873
 7874        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7875
 7876        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7877            BreakpointState::Enabled => Some("Disable"),
 7878            BreakpointState::Disabled => Some("Enable"),
 7879        });
 7880
 7881        let (anchor, breakpoint) =
 7882            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7883
 7884        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7885            menu.on_blur_subscription(Subscription::new(|| {}))
 7886                .context(focus_handle)
 7887                .when(run_to_cursor, |this| {
 7888                    let weak_editor = weak_editor.clone();
 7889                    this.entry("Run to cursor", None, move |window, cx| {
 7890                        weak_editor
 7891                            .update(cx, |editor, cx| {
 7892                                editor.change_selections(
 7893                                    SelectionEffects::no_scroll(),
 7894                                    window,
 7895                                    cx,
 7896                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7897                                );
 7898                            })
 7899                            .ok();
 7900
 7901                        window.dispatch_action(Box::new(RunToCursor), cx);
 7902                    })
 7903                    .separator()
 7904                })
 7905                .when_some(toggle_state_msg, |this, msg| {
 7906                    this.entry(msg, None, {
 7907                        let weak_editor = weak_editor.clone();
 7908                        let breakpoint = breakpoint.clone();
 7909                        move |_window, cx| {
 7910                            weak_editor
 7911                                .update(cx, |this, cx| {
 7912                                    this.edit_breakpoint_at_anchor(
 7913                                        anchor,
 7914                                        breakpoint.as_ref().clone(),
 7915                                        BreakpointEditAction::InvertState,
 7916                                        cx,
 7917                                    );
 7918                                })
 7919                                .log_err();
 7920                        }
 7921                    })
 7922                })
 7923                .entry(set_breakpoint_msg, None, {
 7924                    let weak_editor = weak_editor.clone();
 7925                    let breakpoint = breakpoint.clone();
 7926                    move |_window, cx| {
 7927                        weak_editor
 7928                            .update(cx, |this, cx| {
 7929                                this.edit_breakpoint_at_anchor(
 7930                                    anchor,
 7931                                    breakpoint.as_ref().clone(),
 7932                                    BreakpointEditAction::Toggle,
 7933                                    cx,
 7934                                );
 7935                            })
 7936                            .log_err();
 7937                    }
 7938                })
 7939                .entry(log_breakpoint_msg, None, {
 7940                    let breakpoint = breakpoint.clone();
 7941                    let weak_editor = weak_editor.clone();
 7942                    move |window, cx| {
 7943                        weak_editor
 7944                            .update(cx, |this, cx| {
 7945                                this.add_edit_breakpoint_block(
 7946                                    anchor,
 7947                                    breakpoint.as_ref(),
 7948                                    BreakpointPromptEditAction::Log,
 7949                                    window,
 7950                                    cx,
 7951                                );
 7952                            })
 7953                            .log_err();
 7954                    }
 7955                })
 7956                .entry(condition_breakpoint_msg, None, {
 7957                    let breakpoint = breakpoint.clone();
 7958                    let weak_editor = weak_editor.clone();
 7959                    move |window, cx| {
 7960                        weak_editor
 7961                            .update(cx, |this, cx| {
 7962                                this.add_edit_breakpoint_block(
 7963                                    anchor,
 7964                                    breakpoint.as_ref(),
 7965                                    BreakpointPromptEditAction::Condition,
 7966                                    window,
 7967                                    cx,
 7968                                );
 7969                            })
 7970                            .log_err();
 7971                    }
 7972                })
 7973                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7974                    weak_editor
 7975                        .update(cx, |this, cx| {
 7976                            this.add_edit_breakpoint_block(
 7977                                anchor,
 7978                                breakpoint.as_ref(),
 7979                                BreakpointPromptEditAction::HitCondition,
 7980                                window,
 7981                                cx,
 7982                            );
 7983                        })
 7984                        .log_err();
 7985                })
 7986        })
 7987    }
 7988
 7989    fn render_breakpoint(
 7990        &self,
 7991        position: Anchor,
 7992        row: DisplayRow,
 7993        breakpoint: &Breakpoint,
 7994        state: Option<BreakpointSessionState>,
 7995        cx: &mut Context<Self>,
 7996    ) -> IconButton {
 7997        let is_rejected = state.is_some_and(|s| !s.verified);
 7998        // Is it a breakpoint that shows up when hovering over gutter?
 7999        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8000            (false, false),
 8001            |PhantomBreakpointIndicator {
 8002                 is_active,
 8003                 display_row,
 8004                 collides_with_existing_breakpoint,
 8005             }| {
 8006                (
 8007                    is_active && display_row == row,
 8008                    collides_with_existing_breakpoint,
 8009                )
 8010            },
 8011        );
 8012
 8013        let (color, icon) = {
 8014            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8015                (false, false) => ui::IconName::DebugBreakpoint,
 8016                (true, false) => ui::IconName::DebugLogBreakpoint,
 8017                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8018                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8019            };
 8020
 8021            let color = if is_phantom {
 8022                Color::Hint
 8023            } else if is_rejected {
 8024                Color::Disabled
 8025            } else {
 8026                Color::Debugger
 8027            };
 8028
 8029            (color, icon)
 8030        };
 8031
 8032        let breakpoint = Arc::from(breakpoint.clone());
 8033
 8034        let alt_as_text = gpui::Keystroke {
 8035            modifiers: Modifiers::secondary_key(),
 8036            ..Default::default()
 8037        };
 8038        let primary_action_text = if breakpoint.is_disabled() {
 8039            "Enable breakpoint"
 8040        } else if is_phantom && !collides_with_existing {
 8041            "Set breakpoint"
 8042        } else {
 8043            "Unset breakpoint"
 8044        };
 8045        let focus_handle = self.focus_handle.clone();
 8046
 8047        let meta = if is_rejected {
 8048            SharedString::from("No executable code is associated with this line.")
 8049        } else if collides_with_existing && !breakpoint.is_disabled() {
 8050            SharedString::from(format!(
 8051                "{alt_as_text}-click to disable,\nright-click for more options."
 8052            ))
 8053        } else {
 8054            SharedString::from("Right-click for more options.")
 8055        };
 8056        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8057            .icon_size(IconSize::XSmall)
 8058            .size(ui::ButtonSize::None)
 8059            .when(is_rejected, |this| {
 8060                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8061            })
 8062            .icon_color(color)
 8063            .style(ButtonStyle::Transparent)
 8064            .on_click(cx.listener({
 8065                let breakpoint = breakpoint.clone();
 8066
 8067                move |editor, event: &ClickEvent, window, cx| {
 8068                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8069                        BreakpointEditAction::InvertState
 8070                    } else {
 8071                        BreakpointEditAction::Toggle
 8072                    };
 8073
 8074                    window.focus(&editor.focus_handle(cx));
 8075                    editor.edit_breakpoint_at_anchor(
 8076                        position,
 8077                        breakpoint.as_ref().clone(),
 8078                        edit_action,
 8079                        cx,
 8080                    );
 8081                }
 8082            }))
 8083            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8084                editor.set_breakpoint_context_menu(
 8085                    row,
 8086                    Some(position),
 8087                    event.down.position,
 8088                    window,
 8089                    cx,
 8090                );
 8091            }))
 8092            .tooltip(move |window, cx| {
 8093                Tooltip::with_meta_in(
 8094                    primary_action_text,
 8095                    Some(&ToggleBreakpoint),
 8096                    meta.clone(),
 8097                    &focus_handle,
 8098                    window,
 8099                    cx,
 8100                )
 8101            })
 8102    }
 8103
 8104    fn build_tasks_context(
 8105        project: &Entity<Project>,
 8106        buffer: &Entity<Buffer>,
 8107        buffer_row: u32,
 8108        tasks: &Arc<RunnableTasks>,
 8109        cx: &mut Context<Self>,
 8110    ) -> Task<Option<task::TaskContext>> {
 8111        let position = Point::new(buffer_row, tasks.column);
 8112        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8113        let location = Location {
 8114            buffer: buffer.clone(),
 8115            range: range_start..range_start,
 8116        };
 8117        // Fill in the environmental variables from the tree-sitter captures
 8118        let mut captured_task_variables = TaskVariables::default();
 8119        for (capture_name, value) in tasks.extra_variables.clone() {
 8120            captured_task_variables.insert(
 8121                task::VariableName::Custom(capture_name.into()),
 8122                value.clone(),
 8123            );
 8124        }
 8125        project.update(cx, |project, cx| {
 8126            project.task_store().update(cx, |task_store, cx| {
 8127                task_store.task_context_for_location(captured_task_variables, location, cx)
 8128            })
 8129        })
 8130    }
 8131
 8132    pub fn spawn_nearest_task(
 8133        &mut self,
 8134        action: &SpawnNearestTask,
 8135        window: &mut Window,
 8136        cx: &mut Context<Self>,
 8137    ) {
 8138        let Some((workspace, _)) = self.workspace.clone() else {
 8139            return;
 8140        };
 8141        let Some(project) = self.project.clone() else {
 8142            return;
 8143        };
 8144
 8145        // Try to find a closest, enclosing node using tree-sitter that has a
 8146        // task
 8147        let Some((buffer, buffer_row, tasks)) = self
 8148            .find_enclosing_node_task(cx)
 8149            // Or find the task that's closest in row-distance.
 8150            .or_else(|| self.find_closest_task(cx))
 8151        else {
 8152            return;
 8153        };
 8154
 8155        let reveal_strategy = action.reveal;
 8156        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8157        cx.spawn_in(window, async move |_, cx| {
 8158            let context = task_context.await?;
 8159            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8160
 8161            let resolved = &mut resolved_task.resolved;
 8162            resolved.reveal = reveal_strategy;
 8163
 8164            workspace
 8165                .update_in(cx, |workspace, window, cx| {
 8166                    workspace.schedule_resolved_task(
 8167                        task_source_kind,
 8168                        resolved_task,
 8169                        false,
 8170                        window,
 8171                        cx,
 8172                    );
 8173                })
 8174                .ok()
 8175        })
 8176        .detach();
 8177    }
 8178
 8179    fn find_closest_task(
 8180        &mut self,
 8181        cx: &mut Context<Self>,
 8182    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8183        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8184
 8185        let ((buffer_id, row), tasks) = self
 8186            .tasks
 8187            .iter()
 8188            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8189
 8190        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8191        let tasks = Arc::new(tasks.to_owned());
 8192        Some((buffer, *row, tasks))
 8193    }
 8194
 8195    fn find_enclosing_node_task(
 8196        &mut self,
 8197        cx: &mut Context<Self>,
 8198    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8199        let snapshot = self.buffer.read(cx).snapshot(cx);
 8200        let offset = self.selections.newest::<usize>(cx).head();
 8201        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8202        let buffer_id = excerpt.buffer().remote_id();
 8203
 8204        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8205        let mut cursor = layer.node().walk();
 8206
 8207        while cursor.goto_first_child_for_byte(offset).is_some() {
 8208            if cursor.node().end_byte() == offset {
 8209                cursor.goto_next_sibling();
 8210            }
 8211        }
 8212
 8213        // Ascend to the smallest ancestor that contains the range and has a task.
 8214        loop {
 8215            let node = cursor.node();
 8216            let node_range = node.byte_range();
 8217            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8218
 8219            // Check if this node contains our offset
 8220            if node_range.start <= offset && node_range.end >= offset {
 8221                // If it contains offset, check for task
 8222                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8223                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8224                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8225                }
 8226            }
 8227
 8228            if !cursor.goto_parent() {
 8229                break;
 8230            }
 8231        }
 8232        None
 8233    }
 8234
 8235    fn render_run_indicator(
 8236        &self,
 8237        _style: &EditorStyle,
 8238        is_active: bool,
 8239        row: DisplayRow,
 8240        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8241        cx: &mut Context<Self>,
 8242    ) -> IconButton {
 8243        let color = Color::Muted;
 8244        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8245
 8246        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8247            .shape(ui::IconButtonShape::Square)
 8248            .icon_size(IconSize::XSmall)
 8249            .icon_color(color)
 8250            .toggle_state(is_active)
 8251            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8252                let quick_launch = e.down.button == MouseButton::Left;
 8253                window.focus(&editor.focus_handle(cx));
 8254                editor.toggle_code_actions(
 8255                    &ToggleCodeActions {
 8256                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8257                        quick_launch,
 8258                    },
 8259                    window,
 8260                    cx,
 8261                );
 8262            }))
 8263            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8264                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8265            }))
 8266    }
 8267
 8268    pub fn context_menu_visible(&self) -> bool {
 8269        !self.edit_prediction_preview_is_active()
 8270            && self
 8271                .context_menu
 8272                .borrow()
 8273                .as_ref()
 8274                .map_or(false, |menu| menu.visible())
 8275    }
 8276
 8277    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8278        self.context_menu
 8279            .borrow()
 8280            .as_ref()
 8281            .map(|menu| menu.origin())
 8282    }
 8283
 8284    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8285        self.context_menu_options = Some(options);
 8286    }
 8287
 8288    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8289    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8290
 8291    fn render_edit_prediction_popover(
 8292        &mut self,
 8293        text_bounds: &Bounds<Pixels>,
 8294        content_origin: gpui::Point<Pixels>,
 8295        right_margin: Pixels,
 8296        editor_snapshot: &EditorSnapshot,
 8297        visible_row_range: Range<DisplayRow>,
 8298        scroll_top: f32,
 8299        scroll_bottom: f32,
 8300        line_layouts: &[LineWithInvisibles],
 8301        line_height: Pixels,
 8302        scroll_pixel_position: gpui::Point<Pixels>,
 8303        newest_selection_head: Option<DisplayPoint>,
 8304        editor_width: Pixels,
 8305        style: &EditorStyle,
 8306        window: &mut Window,
 8307        cx: &mut App,
 8308    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8309        if self.mode().is_minimap() {
 8310            return None;
 8311        }
 8312        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8313
 8314        if self.edit_prediction_visible_in_cursor_popover(true) {
 8315            return None;
 8316        }
 8317
 8318        match &active_inline_completion.completion {
 8319            InlineCompletion::Move { target, .. } => {
 8320                let target_display_point = target.to_display_point(editor_snapshot);
 8321
 8322                if self.edit_prediction_requires_modifier() {
 8323                    if !self.edit_prediction_preview_is_active() {
 8324                        return None;
 8325                    }
 8326
 8327                    self.render_edit_prediction_modifier_jump_popover(
 8328                        text_bounds,
 8329                        content_origin,
 8330                        visible_row_range,
 8331                        line_layouts,
 8332                        line_height,
 8333                        scroll_pixel_position,
 8334                        newest_selection_head,
 8335                        target_display_point,
 8336                        window,
 8337                        cx,
 8338                    )
 8339                } else {
 8340                    self.render_edit_prediction_eager_jump_popover(
 8341                        text_bounds,
 8342                        content_origin,
 8343                        editor_snapshot,
 8344                        visible_row_range,
 8345                        scroll_top,
 8346                        scroll_bottom,
 8347                        line_height,
 8348                        scroll_pixel_position,
 8349                        target_display_point,
 8350                        editor_width,
 8351                        window,
 8352                        cx,
 8353                    )
 8354                }
 8355            }
 8356            InlineCompletion::Edit {
 8357                display_mode: EditDisplayMode::Inline,
 8358                ..
 8359            } => None,
 8360            InlineCompletion::Edit {
 8361                display_mode: EditDisplayMode::TabAccept,
 8362                edits,
 8363                ..
 8364            } => {
 8365                let range = &edits.first()?.0;
 8366                let target_display_point = range.end.to_display_point(editor_snapshot);
 8367
 8368                self.render_edit_prediction_end_of_line_popover(
 8369                    "Accept",
 8370                    editor_snapshot,
 8371                    visible_row_range,
 8372                    target_display_point,
 8373                    line_height,
 8374                    scroll_pixel_position,
 8375                    content_origin,
 8376                    editor_width,
 8377                    window,
 8378                    cx,
 8379                )
 8380            }
 8381            InlineCompletion::Edit {
 8382                edits,
 8383                edit_preview,
 8384                display_mode: EditDisplayMode::DiffPopover,
 8385                snapshot,
 8386            } => self.render_edit_prediction_diff_popover(
 8387                text_bounds,
 8388                content_origin,
 8389                right_margin,
 8390                editor_snapshot,
 8391                visible_row_range,
 8392                line_layouts,
 8393                line_height,
 8394                scroll_pixel_position,
 8395                newest_selection_head,
 8396                editor_width,
 8397                style,
 8398                edits,
 8399                edit_preview,
 8400                snapshot,
 8401                window,
 8402                cx,
 8403            ),
 8404        }
 8405    }
 8406
 8407    fn render_edit_prediction_modifier_jump_popover(
 8408        &mut self,
 8409        text_bounds: &Bounds<Pixels>,
 8410        content_origin: gpui::Point<Pixels>,
 8411        visible_row_range: Range<DisplayRow>,
 8412        line_layouts: &[LineWithInvisibles],
 8413        line_height: Pixels,
 8414        scroll_pixel_position: gpui::Point<Pixels>,
 8415        newest_selection_head: Option<DisplayPoint>,
 8416        target_display_point: DisplayPoint,
 8417        window: &mut Window,
 8418        cx: &mut App,
 8419    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8420        let scrolled_content_origin =
 8421            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8422
 8423        const SCROLL_PADDING_Y: Pixels = px(12.);
 8424
 8425        if target_display_point.row() < visible_row_range.start {
 8426            return self.render_edit_prediction_scroll_popover(
 8427                |_| SCROLL_PADDING_Y,
 8428                IconName::ArrowUp,
 8429                visible_row_range,
 8430                line_layouts,
 8431                newest_selection_head,
 8432                scrolled_content_origin,
 8433                window,
 8434                cx,
 8435            );
 8436        } else if target_display_point.row() >= visible_row_range.end {
 8437            return self.render_edit_prediction_scroll_popover(
 8438                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8439                IconName::ArrowDown,
 8440                visible_row_range,
 8441                line_layouts,
 8442                newest_selection_head,
 8443                scrolled_content_origin,
 8444                window,
 8445                cx,
 8446            );
 8447        }
 8448
 8449        const POLE_WIDTH: Pixels = px(2.);
 8450
 8451        let line_layout =
 8452            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8453        let target_column = target_display_point.column() as usize;
 8454
 8455        let target_x = line_layout.x_for_index(target_column);
 8456        let target_y =
 8457            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8458
 8459        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8460
 8461        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8462        border_color.l += 0.001;
 8463
 8464        let mut element = v_flex()
 8465            .items_end()
 8466            .when(flag_on_right, |el| el.items_start())
 8467            .child(if flag_on_right {
 8468                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8469                    .rounded_bl(px(0.))
 8470                    .rounded_tl(px(0.))
 8471                    .border_l_2()
 8472                    .border_color(border_color)
 8473            } else {
 8474                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8475                    .rounded_br(px(0.))
 8476                    .rounded_tr(px(0.))
 8477                    .border_r_2()
 8478                    .border_color(border_color)
 8479            })
 8480            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8481            .into_any();
 8482
 8483        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8484
 8485        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8486            - point(
 8487                if flag_on_right {
 8488                    POLE_WIDTH
 8489                } else {
 8490                    size.width - POLE_WIDTH
 8491                },
 8492                size.height - line_height,
 8493            );
 8494
 8495        origin.x = origin.x.max(content_origin.x);
 8496
 8497        element.prepaint_at(origin, window, cx);
 8498
 8499        Some((element, origin))
 8500    }
 8501
 8502    fn render_edit_prediction_scroll_popover(
 8503        &mut self,
 8504        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8505        scroll_icon: IconName,
 8506        visible_row_range: Range<DisplayRow>,
 8507        line_layouts: &[LineWithInvisibles],
 8508        newest_selection_head: Option<DisplayPoint>,
 8509        scrolled_content_origin: gpui::Point<Pixels>,
 8510        window: &mut Window,
 8511        cx: &mut App,
 8512    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8513        let mut element = self
 8514            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8515            .into_any();
 8516
 8517        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8518
 8519        let cursor = newest_selection_head?;
 8520        let cursor_row_layout =
 8521            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8522        let cursor_column = cursor.column() as usize;
 8523
 8524        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8525
 8526        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8527
 8528        element.prepaint_at(origin, window, cx);
 8529        Some((element, origin))
 8530    }
 8531
 8532    fn render_edit_prediction_eager_jump_popover(
 8533        &mut self,
 8534        text_bounds: &Bounds<Pixels>,
 8535        content_origin: gpui::Point<Pixels>,
 8536        editor_snapshot: &EditorSnapshot,
 8537        visible_row_range: Range<DisplayRow>,
 8538        scroll_top: f32,
 8539        scroll_bottom: f32,
 8540        line_height: Pixels,
 8541        scroll_pixel_position: gpui::Point<Pixels>,
 8542        target_display_point: DisplayPoint,
 8543        editor_width: Pixels,
 8544        window: &mut Window,
 8545        cx: &mut App,
 8546    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8547        if target_display_point.row().as_f32() < scroll_top {
 8548            let mut element = self
 8549                .render_edit_prediction_line_popover(
 8550                    "Jump to Edit",
 8551                    Some(IconName::ArrowUp),
 8552                    window,
 8553                    cx,
 8554                )?
 8555                .into_any();
 8556
 8557            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8558            let offset = point(
 8559                (text_bounds.size.width - size.width) / 2.,
 8560                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8561            );
 8562
 8563            let origin = text_bounds.origin + offset;
 8564            element.prepaint_at(origin, window, cx);
 8565            Some((element, origin))
 8566        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8567            let mut element = self
 8568                .render_edit_prediction_line_popover(
 8569                    "Jump to Edit",
 8570                    Some(IconName::ArrowDown),
 8571                    window,
 8572                    cx,
 8573                )?
 8574                .into_any();
 8575
 8576            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8577            let offset = point(
 8578                (text_bounds.size.width - size.width) / 2.,
 8579                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8580            );
 8581
 8582            let origin = text_bounds.origin + offset;
 8583            element.prepaint_at(origin, window, cx);
 8584            Some((element, origin))
 8585        } else {
 8586            self.render_edit_prediction_end_of_line_popover(
 8587                "Jump to Edit",
 8588                editor_snapshot,
 8589                visible_row_range,
 8590                target_display_point,
 8591                line_height,
 8592                scroll_pixel_position,
 8593                content_origin,
 8594                editor_width,
 8595                window,
 8596                cx,
 8597            )
 8598        }
 8599    }
 8600
 8601    fn render_edit_prediction_end_of_line_popover(
 8602        self: &mut Editor,
 8603        label: &'static str,
 8604        editor_snapshot: &EditorSnapshot,
 8605        visible_row_range: Range<DisplayRow>,
 8606        target_display_point: DisplayPoint,
 8607        line_height: Pixels,
 8608        scroll_pixel_position: gpui::Point<Pixels>,
 8609        content_origin: gpui::Point<Pixels>,
 8610        editor_width: Pixels,
 8611        window: &mut Window,
 8612        cx: &mut App,
 8613    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8614        let target_line_end = DisplayPoint::new(
 8615            target_display_point.row(),
 8616            editor_snapshot.line_len(target_display_point.row()),
 8617        );
 8618
 8619        let mut element = self
 8620            .render_edit_prediction_line_popover(label, None, window, cx)?
 8621            .into_any();
 8622
 8623        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8624
 8625        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8626
 8627        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8628        let mut origin = start_point
 8629            + line_origin
 8630            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8631        origin.x = origin.x.max(content_origin.x);
 8632
 8633        let max_x = content_origin.x + editor_width - size.width;
 8634
 8635        if origin.x > max_x {
 8636            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8637
 8638            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8639                origin.y += offset;
 8640                IconName::ArrowUp
 8641            } else {
 8642                origin.y -= offset;
 8643                IconName::ArrowDown
 8644            };
 8645
 8646            element = self
 8647                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8648                .into_any();
 8649
 8650            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8651
 8652            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8653        }
 8654
 8655        element.prepaint_at(origin, window, cx);
 8656        Some((element, origin))
 8657    }
 8658
 8659    fn render_edit_prediction_diff_popover(
 8660        self: &Editor,
 8661        text_bounds: &Bounds<Pixels>,
 8662        content_origin: gpui::Point<Pixels>,
 8663        right_margin: Pixels,
 8664        editor_snapshot: &EditorSnapshot,
 8665        visible_row_range: Range<DisplayRow>,
 8666        line_layouts: &[LineWithInvisibles],
 8667        line_height: Pixels,
 8668        scroll_pixel_position: gpui::Point<Pixels>,
 8669        newest_selection_head: Option<DisplayPoint>,
 8670        editor_width: Pixels,
 8671        style: &EditorStyle,
 8672        edits: &Vec<(Range<Anchor>, String)>,
 8673        edit_preview: &Option<language::EditPreview>,
 8674        snapshot: &language::BufferSnapshot,
 8675        window: &mut Window,
 8676        cx: &mut App,
 8677    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8678        let edit_start = edits
 8679            .first()
 8680            .unwrap()
 8681            .0
 8682            .start
 8683            .to_display_point(editor_snapshot);
 8684        let edit_end = edits
 8685            .last()
 8686            .unwrap()
 8687            .0
 8688            .end
 8689            .to_display_point(editor_snapshot);
 8690
 8691        let is_visible = visible_row_range.contains(&edit_start.row())
 8692            || visible_row_range.contains(&edit_end.row());
 8693        if !is_visible {
 8694            return None;
 8695        }
 8696
 8697        let highlighted_edits =
 8698            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8699
 8700        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8701        let line_count = highlighted_edits.text.lines().count();
 8702
 8703        const BORDER_WIDTH: Pixels = px(1.);
 8704
 8705        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8706        let has_keybind = keybind.is_some();
 8707
 8708        let mut element = h_flex()
 8709            .items_start()
 8710            .child(
 8711                h_flex()
 8712                    .bg(cx.theme().colors().editor_background)
 8713                    .border(BORDER_WIDTH)
 8714                    .shadow_sm()
 8715                    .border_color(cx.theme().colors().border)
 8716                    .rounded_l_lg()
 8717                    .when(line_count > 1, |el| el.rounded_br_lg())
 8718                    .pr_1()
 8719                    .child(styled_text),
 8720            )
 8721            .child(
 8722                h_flex()
 8723                    .h(line_height + BORDER_WIDTH * 2.)
 8724                    .px_1p5()
 8725                    .gap_1()
 8726                    // Workaround: For some reason, there's a gap if we don't do this
 8727                    .ml(-BORDER_WIDTH)
 8728                    .shadow(vec![gpui::BoxShadow {
 8729                        color: gpui::black().opacity(0.05),
 8730                        offset: point(px(1.), px(1.)),
 8731                        blur_radius: px(2.),
 8732                        spread_radius: px(0.),
 8733                    }])
 8734                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8735                    .border(BORDER_WIDTH)
 8736                    .border_color(cx.theme().colors().border)
 8737                    .rounded_r_lg()
 8738                    .id("edit_prediction_diff_popover_keybind")
 8739                    .when(!has_keybind, |el| {
 8740                        let status_colors = cx.theme().status();
 8741
 8742                        el.bg(status_colors.error_background)
 8743                            .border_color(status_colors.error.opacity(0.6))
 8744                            .child(Icon::new(IconName::Info).color(Color::Error))
 8745                            .cursor_default()
 8746                            .hoverable_tooltip(move |_window, cx| {
 8747                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8748                            })
 8749                    })
 8750                    .children(keybind),
 8751            )
 8752            .into_any();
 8753
 8754        let longest_row =
 8755            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8756        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8757            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8758        } else {
 8759            layout_line(
 8760                longest_row,
 8761                editor_snapshot,
 8762                style,
 8763                editor_width,
 8764                |_| false,
 8765                window,
 8766                cx,
 8767            )
 8768            .width
 8769        };
 8770
 8771        let viewport_bounds =
 8772            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8773                right: -right_margin,
 8774                ..Default::default()
 8775            });
 8776
 8777        let x_after_longest =
 8778            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8779                - scroll_pixel_position.x;
 8780
 8781        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8782
 8783        // Fully visible if it can be displayed within the window (allow overlapping other
 8784        // panes). However, this is only allowed if the popover starts within text_bounds.
 8785        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8786            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8787
 8788        let mut origin = if can_position_to_the_right {
 8789            point(
 8790                x_after_longest,
 8791                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8792                    - scroll_pixel_position.y,
 8793            )
 8794        } else {
 8795            let cursor_row = newest_selection_head.map(|head| head.row());
 8796            let above_edit = edit_start
 8797                .row()
 8798                .0
 8799                .checked_sub(line_count as u32)
 8800                .map(DisplayRow);
 8801            let below_edit = Some(edit_end.row() + 1);
 8802            let above_cursor =
 8803                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8804            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8805
 8806            // Place the edit popover adjacent to the edit if there is a location
 8807            // available that is onscreen and does not obscure the cursor. Otherwise,
 8808            // place it adjacent to the cursor.
 8809            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8810                .into_iter()
 8811                .flatten()
 8812                .find(|&start_row| {
 8813                    let end_row = start_row + line_count as u32;
 8814                    visible_row_range.contains(&start_row)
 8815                        && visible_row_range.contains(&end_row)
 8816                        && cursor_row.map_or(true, |cursor_row| {
 8817                            !((start_row..end_row).contains(&cursor_row))
 8818                        })
 8819                })?;
 8820
 8821            content_origin
 8822                + point(
 8823                    -scroll_pixel_position.x,
 8824                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8825                )
 8826        };
 8827
 8828        origin.x -= BORDER_WIDTH;
 8829
 8830        window.defer_draw(element, origin, 1);
 8831
 8832        // Do not return an element, since it will already be drawn due to defer_draw.
 8833        None
 8834    }
 8835
 8836    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8837        px(30.)
 8838    }
 8839
 8840    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8841        if self.read_only(cx) {
 8842            cx.theme().players().read_only()
 8843        } else {
 8844            self.style.as_ref().unwrap().local_player
 8845        }
 8846    }
 8847
 8848    fn render_edit_prediction_accept_keybind(
 8849        &self,
 8850        window: &mut Window,
 8851        cx: &App,
 8852    ) -> Option<AnyElement> {
 8853        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8854        let accept_keystroke = accept_binding.keystroke()?;
 8855
 8856        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8857
 8858        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8859            Color::Accent
 8860        } else {
 8861            Color::Muted
 8862        };
 8863
 8864        h_flex()
 8865            .px_0p5()
 8866            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8867            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8868            .text_size(TextSize::XSmall.rems(cx))
 8869            .child(h_flex().children(ui::render_modifiers(
 8870                &accept_keystroke.modifiers,
 8871                PlatformStyle::platform(),
 8872                Some(modifiers_color),
 8873                Some(IconSize::XSmall.rems().into()),
 8874                true,
 8875            )))
 8876            .when(is_platform_style_mac, |parent| {
 8877                parent.child(accept_keystroke.key.clone())
 8878            })
 8879            .when(!is_platform_style_mac, |parent| {
 8880                parent.child(
 8881                    Key::new(
 8882                        util::capitalize(&accept_keystroke.key),
 8883                        Some(Color::Default),
 8884                    )
 8885                    .size(Some(IconSize::XSmall.rems().into())),
 8886                )
 8887            })
 8888            .into_any()
 8889            .into()
 8890    }
 8891
 8892    fn render_edit_prediction_line_popover(
 8893        &self,
 8894        label: impl Into<SharedString>,
 8895        icon: Option<IconName>,
 8896        window: &mut Window,
 8897        cx: &App,
 8898    ) -> Option<Stateful<Div>> {
 8899        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8900
 8901        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8902        let has_keybind = keybind.is_some();
 8903
 8904        let result = h_flex()
 8905            .id("ep-line-popover")
 8906            .py_0p5()
 8907            .pl_1()
 8908            .pr(padding_right)
 8909            .gap_1()
 8910            .rounded_md()
 8911            .border_1()
 8912            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8913            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8914            .shadow_sm()
 8915            .when(!has_keybind, |el| {
 8916                let status_colors = cx.theme().status();
 8917
 8918                el.bg(status_colors.error_background)
 8919                    .border_color(status_colors.error.opacity(0.6))
 8920                    .pl_2()
 8921                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8922                    .cursor_default()
 8923                    .hoverable_tooltip(move |_window, cx| {
 8924                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8925                    })
 8926            })
 8927            .children(keybind)
 8928            .child(
 8929                Label::new(label)
 8930                    .size(LabelSize::Small)
 8931                    .when(!has_keybind, |el| {
 8932                        el.color(cx.theme().status().error.into()).strikethrough()
 8933                    }),
 8934            )
 8935            .when(!has_keybind, |el| {
 8936                el.child(
 8937                    h_flex().ml_1().child(
 8938                        Icon::new(IconName::Info)
 8939                            .size(IconSize::Small)
 8940                            .color(cx.theme().status().error.into()),
 8941                    ),
 8942                )
 8943            })
 8944            .when_some(icon, |element, icon| {
 8945                element.child(
 8946                    div()
 8947                        .mt(px(1.5))
 8948                        .child(Icon::new(icon).size(IconSize::Small)),
 8949                )
 8950            });
 8951
 8952        Some(result)
 8953    }
 8954
 8955    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8956        let accent_color = cx.theme().colors().text_accent;
 8957        let editor_bg_color = cx.theme().colors().editor_background;
 8958        editor_bg_color.blend(accent_color.opacity(0.1))
 8959    }
 8960
 8961    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8962        let accent_color = cx.theme().colors().text_accent;
 8963        let editor_bg_color = cx.theme().colors().editor_background;
 8964        editor_bg_color.blend(accent_color.opacity(0.6))
 8965    }
 8966
 8967    fn render_edit_prediction_cursor_popover(
 8968        &self,
 8969        min_width: Pixels,
 8970        max_width: Pixels,
 8971        cursor_point: Point,
 8972        style: &EditorStyle,
 8973        accept_keystroke: Option<&gpui::Keystroke>,
 8974        _window: &Window,
 8975        cx: &mut Context<Editor>,
 8976    ) -> Option<AnyElement> {
 8977        let provider = self.edit_prediction_provider.as_ref()?;
 8978
 8979        if provider.provider.needs_terms_acceptance(cx) {
 8980            return Some(
 8981                h_flex()
 8982                    .min_w(min_width)
 8983                    .flex_1()
 8984                    .px_2()
 8985                    .py_1()
 8986                    .gap_3()
 8987                    .elevation_2(cx)
 8988                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8989                    .id("accept-terms")
 8990                    .cursor_pointer()
 8991                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8992                    .on_click(cx.listener(|this, _event, window, cx| {
 8993                        cx.stop_propagation();
 8994                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8995                        window.dispatch_action(
 8996                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8997                            cx,
 8998                        );
 8999                    }))
 9000                    .child(
 9001                        h_flex()
 9002                            .flex_1()
 9003                            .gap_2()
 9004                            .child(Icon::new(IconName::ZedPredict))
 9005                            .child(Label::new("Accept Terms of Service"))
 9006                            .child(div().w_full())
 9007                            .child(
 9008                                Icon::new(IconName::ArrowUpRight)
 9009                                    .color(Color::Muted)
 9010                                    .size(IconSize::Small),
 9011                            )
 9012                            .into_any_element(),
 9013                    )
 9014                    .into_any(),
 9015            );
 9016        }
 9017
 9018        let is_refreshing = provider.provider.is_refreshing(cx);
 9019
 9020        fn pending_completion_container() -> Div {
 9021            h_flex()
 9022                .h_full()
 9023                .flex_1()
 9024                .gap_2()
 9025                .child(Icon::new(IconName::ZedPredict))
 9026        }
 9027
 9028        let completion = match &self.active_inline_completion {
 9029            Some(prediction) => {
 9030                if !self.has_visible_completions_menu() {
 9031                    const RADIUS: Pixels = px(6.);
 9032                    const BORDER_WIDTH: Pixels = px(1.);
 9033
 9034                    return Some(
 9035                        h_flex()
 9036                            .elevation_2(cx)
 9037                            .border(BORDER_WIDTH)
 9038                            .border_color(cx.theme().colors().border)
 9039                            .when(accept_keystroke.is_none(), |el| {
 9040                                el.border_color(cx.theme().status().error)
 9041                            })
 9042                            .rounded(RADIUS)
 9043                            .rounded_tl(px(0.))
 9044                            .overflow_hidden()
 9045                            .child(div().px_1p5().child(match &prediction.completion {
 9046                                InlineCompletion::Move { target, snapshot } => {
 9047                                    use text::ToPoint as _;
 9048                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9049                                    {
 9050                                        Icon::new(IconName::ZedPredictDown)
 9051                                    } else {
 9052                                        Icon::new(IconName::ZedPredictUp)
 9053                                    }
 9054                                }
 9055                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9056                            }))
 9057                            .child(
 9058                                h_flex()
 9059                                    .gap_1()
 9060                                    .py_1()
 9061                                    .px_2()
 9062                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9063                                    .border_l_1()
 9064                                    .border_color(cx.theme().colors().border)
 9065                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9066                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9067                                        el.child(
 9068                                            Label::new("Hold")
 9069                                                .size(LabelSize::Small)
 9070                                                .when(accept_keystroke.is_none(), |el| {
 9071                                                    el.strikethrough()
 9072                                                })
 9073                                                .line_height_style(LineHeightStyle::UiLabel),
 9074                                        )
 9075                                    })
 9076                                    .id("edit_prediction_cursor_popover_keybind")
 9077                                    .when(accept_keystroke.is_none(), |el| {
 9078                                        let status_colors = cx.theme().status();
 9079
 9080                                        el.bg(status_colors.error_background)
 9081                                            .border_color(status_colors.error.opacity(0.6))
 9082                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9083                                            .cursor_default()
 9084                                            .hoverable_tooltip(move |_window, cx| {
 9085                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9086                                                    .into()
 9087                                            })
 9088                                    })
 9089                                    .when_some(
 9090                                        accept_keystroke.as_ref(),
 9091                                        |el, accept_keystroke| {
 9092                                            el.child(h_flex().children(ui::render_modifiers(
 9093                                                &accept_keystroke.modifiers,
 9094                                                PlatformStyle::platform(),
 9095                                                Some(Color::Default),
 9096                                                Some(IconSize::XSmall.rems().into()),
 9097                                                false,
 9098                                            )))
 9099                                        },
 9100                                    ),
 9101                            )
 9102                            .into_any(),
 9103                    );
 9104                }
 9105
 9106                self.render_edit_prediction_cursor_popover_preview(
 9107                    prediction,
 9108                    cursor_point,
 9109                    style,
 9110                    cx,
 9111                )?
 9112            }
 9113
 9114            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9115                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9116                    stale_completion,
 9117                    cursor_point,
 9118                    style,
 9119                    cx,
 9120                )?,
 9121
 9122                None => {
 9123                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9124                }
 9125            },
 9126
 9127            None => pending_completion_container().child(Label::new("No Prediction")),
 9128        };
 9129
 9130        let completion = if is_refreshing {
 9131            completion
 9132                .with_animation(
 9133                    "loading-completion",
 9134                    Animation::new(Duration::from_secs(2))
 9135                        .repeat()
 9136                        .with_easing(pulsating_between(0.4, 0.8)),
 9137                    |label, delta| label.opacity(delta),
 9138                )
 9139                .into_any_element()
 9140        } else {
 9141            completion.into_any_element()
 9142        };
 9143
 9144        let has_completion = self.active_inline_completion.is_some();
 9145
 9146        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9147        Some(
 9148            h_flex()
 9149                .min_w(min_width)
 9150                .max_w(max_width)
 9151                .flex_1()
 9152                .elevation_2(cx)
 9153                .border_color(cx.theme().colors().border)
 9154                .child(
 9155                    div()
 9156                        .flex_1()
 9157                        .py_1()
 9158                        .px_2()
 9159                        .overflow_hidden()
 9160                        .child(completion),
 9161                )
 9162                .when_some(accept_keystroke, |el, accept_keystroke| {
 9163                    if !accept_keystroke.modifiers.modified() {
 9164                        return el;
 9165                    }
 9166
 9167                    el.child(
 9168                        h_flex()
 9169                            .h_full()
 9170                            .border_l_1()
 9171                            .rounded_r_lg()
 9172                            .border_color(cx.theme().colors().border)
 9173                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9174                            .gap_1()
 9175                            .py_1()
 9176                            .px_2()
 9177                            .child(
 9178                                h_flex()
 9179                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9180                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9181                                    .child(h_flex().children(ui::render_modifiers(
 9182                                        &accept_keystroke.modifiers,
 9183                                        PlatformStyle::platform(),
 9184                                        Some(if !has_completion {
 9185                                            Color::Muted
 9186                                        } else {
 9187                                            Color::Default
 9188                                        }),
 9189                                        None,
 9190                                        false,
 9191                                    ))),
 9192                            )
 9193                            .child(Label::new("Preview").into_any_element())
 9194                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9195                    )
 9196                })
 9197                .into_any(),
 9198        )
 9199    }
 9200
 9201    fn render_edit_prediction_cursor_popover_preview(
 9202        &self,
 9203        completion: &InlineCompletionState,
 9204        cursor_point: Point,
 9205        style: &EditorStyle,
 9206        cx: &mut Context<Editor>,
 9207    ) -> Option<Div> {
 9208        use text::ToPoint as _;
 9209
 9210        fn render_relative_row_jump(
 9211            prefix: impl Into<String>,
 9212            current_row: u32,
 9213            target_row: u32,
 9214        ) -> Div {
 9215            let (row_diff, arrow) = if target_row < current_row {
 9216                (current_row - target_row, IconName::ArrowUp)
 9217            } else {
 9218                (target_row - current_row, IconName::ArrowDown)
 9219            };
 9220
 9221            h_flex()
 9222                .child(
 9223                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9224                        .color(Color::Muted)
 9225                        .size(LabelSize::Small),
 9226                )
 9227                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9228        }
 9229
 9230        match &completion.completion {
 9231            InlineCompletion::Move {
 9232                target, snapshot, ..
 9233            } => Some(
 9234                h_flex()
 9235                    .px_2()
 9236                    .gap_2()
 9237                    .flex_1()
 9238                    .child(
 9239                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9240                            Icon::new(IconName::ZedPredictDown)
 9241                        } else {
 9242                            Icon::new(IconName::ZedPredictUp)
 9243                        },
 9244                    )
 9245                    .child(Label::new("Jump to Edit")),
 9246            ),
 9247
 9248            InlineCompletion::Edit {
 9249                edits,
 9250                edit_preview,
 9251                snapshot,
 9252                display_mode: _,
 9253            } => {
 9254                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9255
 9256                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9257                    &snapshot,
 9258                    &edits,
 9259                    edit_preview.as_ref()?,
 9260                    true,
 9261                    cx,
 9262                )
 9263                .first_line_preview();
 9264
 9265                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9266                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9267
 9268                let preview = h_flex()
 9269                    .gap_1()
 9270                    .min_w_16()
 9271                    .child(styled_text)
 9272                    .when(has_more_lines, |parent| parent.child(""));
 9273
 9274                let left = if first_edit_row != cursor_point.row {
 9275                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9276                        .into_any_element()
 9277                } else {
 9278                    Icon::new(IconName::ZedPredict).into_any_element()
 9279                };
 9280
 9281                Some(
 9282                    h_flex()
 9283                        .h_full()
 9284                        .flex_1()
 9285                        .gap_2()
 9286                        .pr_1()
 9287                        .overflow_x_hidden()
 9288                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9289                        .child(left)
 9290                        .child(preview),
 9291                )
 9292            }
 9293        }
 9294    }
 9295
 9296    pub fn render_context_menu(
 9297        &self,
 9298        style: &EditorStyle,
 9299        max_height_in_lines: u32,
 9300        window: &mut Window,
 9301        cx: &mut Context<Editor>,
 9302    ) -> Option<AnyElement> {
 9303        let menu = self.context_menu.borrow();
 9304        let menu = menu.as_ref()?;
 9305        if !menu.visible() {
 9306            return None;
 9307        };
 9308        Some(menu.render(style, max_height_in_lines, window, cx))
 9309    }
 9310
 9311    fn render_context_menu_aside(
 9312        &mut self,
 9313        max_size: Size<Pixels>,
 9314        window: &mut Window,
 9315        cx: &mut Context<Editor>,
 9316    ) -> Option<AnyElement> {
 9317        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9318            if menu.visible() {
 9319                menu.render_aside(max_size, window, cx)
 9320            } else {
 9321                None
 9322            }
 9323        })
 9324    }
 9325
 9326    fn hide_context_menu(
 9327        &mut self,
 9328        window: &mut Window,
 9329        cx: &mut Context<Self>,
 9330    ) -> Option<CodeContextMenu> {
 9331        cx.notify();
 9332        self.completion_tasks.clear();
 9333        let context_menu = self.context_menu.borrow_mut().take();
 9334        self.stale_inline_completion_in_menu.take();
 9335        self.update_visible_inline_completion(window, cx);
 9336        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9337            if let Some(completion_provider) = &self.completion_provider {
 9338                completion_provider.selection_changed(None, window, cx);
 9339            }
 9340        }
 9341        context_menu
 9342    }
 9343
 9344    fn show_snippet_choices(
 9345        &mut self,
 9346        choices: &Vec<String>,
 9347        selection: Range<Anchor>,
 9348        cx: &mut Context<Self>,
 9349    ) {
 9350        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9351            (Some(a), Some(b)) if a == b => a,
 9352            _ => {
 9353                log::error!("expected anchor range to have matching buffer IDs");
 9354                return;
 9355            }
 9356        };
 9357        let multi_buffer = self.buffer().read(cx);
 9358        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9359            return;
 9360        };
 9361
 9362        let id = post_inc(&mut self.next_completion_id);
 9363        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9364        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9365            CompletionsMenu::new_snippet_choices(
 9366                id,
 9367                true,
 9368                choices,
 9369                selection,
 9370                buffer,
 9371                snippet_sort_order,
 9372            ),
 9373        ));
 9374    }
 9375
 9376    pub fn insert_snippet(
 9377        &mut self,
 9378        insertion_ranges: &[Range<usize>],
 9379        snippet: Snippet,
 9380        window: &mut Window,
 9381        cx: &mut Context<Self>,
 9382    ) -> Result<()> {
 9383        struct Tabstop<T> {
 9384            is_end_tabstop: bool,
 9385            ranges: Vec<Range<T>>,
 9386            choices: Option<Vec<String>>,
 9387        }
 9388
 9389        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9390            let snippet_text: Arc<str> = snippet.text.clone().into();
 9391            let edits = insertion_ranges
 9392                .iter()
 9393                .cloned()
 9394                .map(|range| (range, snippet_text.clone()));
 9395            let autoindent_mode = AutoindentMode::Block {
 9396                original_indent_columns: Vec::new(),
 9397            };
 9398            buffer.edit(edits, Some(autoindent_mode), cx);
 9399
 9400            let snapshot = &*buffer.read(cx);
 9401            let snippet = &snippet;
 9402            snippet
 9403                .tabstops
 9404                .iter()
 9405                .map(|tabstop| {
 9406                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9407                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9408                    });
 9409                    let mut tabstop_ranges = tabstop
 9410                        .ranges
 9411                        .iter()
 9412                        .flat_map(|tabstop_range| {
 9413                            let mut delta = 0_isize;
 9414                            insertion_ranges.iter().map(move |insertion_range| {
 9415                                let insertion_start = insertion_range.start as isize + delta;
 9416                                delta +=
 9417                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9418
 9419                                let start = ((insertion_start + tabstop_range.start) as usize)
 9420                                    .min(snapshot.len());
 9421                                let end = ((insertion_start + tabstop_range.end) as usize)
 9422                                    .min(snapshot.len());
 9423                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9424                            })
 9425                        })
 9426                        .collect::<Vec<_>>();
 9427                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9428
 9429                    Tabstop {
 9430                        is_end_tabstop,
 9431                        ranges: tabstop_ranges,
 9432                        choices: tabstop.choices.clone(),
 9433                    }
 9434                })
 9435                .collect::<Vec<_>>()
 9436        });
 9437        if let Some(tabstop) = tabstops.first() {
 9438            self.change_selections(Default::default(), window, cx, |s| {
 9439                // Reverse order so that the first range is the newest created selection.
 9440                // Completions will use it and autoscroll will prioritize it.
 9441                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9442            });
 9443
 9444            if let Some(choices) = &tabstop.choices {
 9445                if let Some(selection) = tabstop.ranges.first() {
 9446                    self.show_snippet_choices(choices, selection.clone(), cx)
 9447                }
 9448            }
 9449
 9450            // If we're already at the last tabstop and it's at the end of the snippet,
 9451            // we're done, we don't need to keep the state around.
 9452            if !tabstop.is_end_tabstop {
 9453                let choices = tabstops
 9454                    .iter()
 9455                    .map(|tabstop| tabstop.choices.clone())
 9456                    .collect();
 9457
 9458                let ranges = tabstops
 9459                    .into_iter()
 9460                    .map(|tabstop| tabstop.ranges)
 9461                    .collect::<Vec<_>>();
 9462
 9463                self.snippet_stack.push(SnippetState {
 9464                    active_index: 0,
 9465                    ranges,
 9466                    choices,
 9467                });
 9468            }
 9469
 9470            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9471            if self.autoclose_regions.is_empty() {
 9472                let snapshot = self.buffer.read(cx).snapshot(cx);
 9473                for selection in &mut self.selections.all::<Point>(cx) {
 9474                    let selection_head = selection.head();
 9475                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9476                        continue;
 9477                    };
 9478
 9479                    let mut bracket_pair = None;
 9480                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9481                    let prev_chars = snapshot
 9482                        .reversed_chars_at(selection_head)
 9483                        .collect::<String>();
 9484                    for (pair, enabled) in scope.brackets() {
 9485                        if enabled
 9486                            && pair.close
 9487                            && prev_chars.starts_with(pair.start.as_str())
 9488                            && next_chars.starts_with(pair.end.as_str())
 9489                        {
 9490                            bracket_pair = Some(pair.clone());
 9491                            break;
 9492                        }
 9493                    }
 9494                    if let Some(pair) = bracket_pair {
 9495                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9496                        let autoclose_enabled =
 9497                            self.use_autoclose && snapshot_settings.use_autoclose;
 9498                        if autoclose_enabled {
 9499                            let start = snapshot.anchor_after(selection_head);
 9500                            let end = snapshot.anchor_after(selection_head);
 9501                            self.autoclose_regions.push(AutocloseRegion {
 9502                                selection_id: selection.id,
 9503                                range: start..end,
 9504                                pair,
 9505                            });
 9506                        }
 9507                    }
 9508                }
 9509            }
 9510        }
 9511        Ok(())
 9512    }
 9513
 9514    pub fn move_to_next_snippet_tabstop(
 9515        &mut self,
 9516        window: &mut Window,
 9517        cx: &mut Context<Self>,
 9518    ) -> bool {
 9519        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9520    }
 9521
 9522    pub fn move_to_prev_snippet_tabstop(
 9523        &mut self,
 9524        window: &mut Window,
 9525        cx: &mut Context<Self>,
 9526    ) -> bool {
 9527        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9528    }
 9529
 9530    pub fn move_to_snippet_tabstop(
 9531        &mut self,
 9532        bias: Bias,
 9533        window: &mut Window,
 9534        cx: &mut Context<Self>,
 9535    ) -> bool {
 9536        if let Some(mut snippet) = self.snippet_stack.pop() {
 9537            match bias {
 9538                Bias::Left => {
 9539                    if snippet.active_index > 0 {
 9540                        snippet.active_index -= 1;
 9541                    } else {
 9542                        self.snippet_stack.push(snippet);
 9543                        return false;
 9544                    }
 9545                }
 9546                Bias::Right => {
 9547                    if snippet.active_index + 1 < snippet.ranges.len() {
 9548                        snippet.active_index += 1;
 9549                    } else {
 9550                        self.snippet_stack.push(snippet);
 9551                        return false;
 9552                    }
 9553                }
 9554            }
 9555            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9556                self.change_selections(Default::default(), window, cx, |s| {
 9557                    // Reverse order so that the first range is the newest created selection.
 9558                    // Completions will use it and autoscroll will prioritize it.
 9559                    s.select_ranges(current_ranges.iter().rev().cloned())
 9560                });
 9561
 9562                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9563                    if let Some(selection) = current_ranges.first() {
 9564                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9565                    }
 9566                }
 9567
 9568                // If snippet state is not at the last tabstop, push it back on the stack
 9569                if snippet.active_index + 1 < snippet.ranges.len() {
 9570                    self.snippet_stack.push(snippet);
 9571                }
 9572                return true;
 9573            }
 9574        }
 9575
 9576        false
 9577    }
 9578
 9579    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9580        self.transact(window, cx, |this, window, cx| {
 9581            this.select_all(&SelectAll, window, cx);
 9582            this.insert("", window, cx);
 9583        });
 9584    }
 9585
 9586    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9587        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9588        self.transact(window, cx, |this, window, cx| {
 9589            this.select_autoclose_pair(window, cx);
 9590            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9591            if !this.linked_edit_ranges.is_empty() {
 9592                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9593                let snapshot = this.buffer.read(cx).snapshot(cx);
 9594
 9595                for selection in selections.iter() {
 9596                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9597                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9598                    if selection_start.buffer_id != selection_end.buffer_id {
 9599                        continue;
 9600                    }
 9601                    if let Some(ranges) =
 9602                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9603                    {
 9604                        for (buffer, entries) in ranges {
 9605                            linked_ranges.entry(buffer).or_default().extend(entries);
 9606                        }
 9607                    }
 9608                }
 9609            }
 9610
 9611            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9612            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9613            for selection in &mut selections {
 9614                if selection.is_empty() {
 9615                    let old_head = selection.head();
 9616                    let mut new_head =
 9617                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9618                            .to_point(&display_map);
 9619                    if let Some((buffer, line_buffer_range)) = display_map
 9620                        .buffer_snapshot
 9621                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9622                    {
 9623                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9624                        let indent_len = match indent_size.kind {
 9625                            IndentKind::Space => {
 9626                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9627                            }
 9628                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9629                        };
 9630                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9631                            let indent_len = indent_len.get();
 9632                            new_head = cmp::min(
 9633                                new_head,
 9634                                MultiBufferPoint::new(
 9635                                    old_head.row,
 9636                                    ((old_head.column - 1) / indent_len) * indent_len,
 9637                                ),
 9638                            );
 9639                        }
 9640                    }
 9641
 9642                    selection.set_head(new_head, SelectionGoal::None);
 9643                }
 9644            }
 9645
 9646            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9647            this.insert("", window, cx);
 9648            let empty_str: Arc<str> = Arc::from("");
 9649            for (buffer, edits) in linked_ranges {
 9650                let snapshot = buffer.read(cx).snapshot();
 9651                use text::ToPoint as TP;
 9652
 9653                let edits = edits
 9654                    .into_iter()
 9655                    .map(|range| {
 9656                        let end_point = TP::to_point(&range.end, &snapshot);
 9657                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9658
 9659                        if end_point == start_point {
 9660                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9661                                .saturating_sub(1);
 9662                            start_point =
 9663                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9664                        };
 9665
 9666                        (start_point..end_point, empty_str.clone())
 9667                    })
 9668                    .sorted_by_key(|(range, _)| range.start)
 9669                    .collect::<Vec<_>>();
 9670                buffer.update(cx, |this, cx| {
 9671                    this.edit(edits, None, cx);
 9672                })
 9673            }
 9674            this.refresh_inline_completion(true, false, window, cx);
 9675            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9676        });
 9677    }
 9678
 9679    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9680        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9681        self.transact(window, cx, |this, window, cx| {
 9682            this.change_selections(Default::default(), window, cx, |s| {
 9683                s.move_with(|map, selection| {
 9684                    if selection.is_empty() {
 9685                        let cursor = movement::right(map, selection.head());
 9686                        selection.end = cursor;
 9687                        selection.reversed = true;
 9688                        selection.goal = SelectionGoal::None;
 9689                    }
 9690                })
 9691            });
 9692            this.insert("", window, cx);
 9693            this.refresh_inline_completion(true, false, window, cx);
 9694        });
 9695    }
 9696
 9697    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9698        if self.mode.is_single_line() {
 9699            cx.propagate();
 9700            return;
 9701        }
 9702
 9703        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9704        if self.move_to_prev_snippet_tabstop(window, cx) {
 9705            return;
 9706        }
 9707        self.outdent(&Outdent, window, cx);
 9708    }
 9709
 9710    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9711        if self.mode.is_single_line() {
 9712            cx.propagate();
 9713            return;
 9714        }
 9715
 9716        if self.move_to_next_snippet_tabstop(window, cx) {
 9717            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9718            return;
 9719        }
 9720        if self.read_only(cx) {
 9721            return;
 9722        }
 9723        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9724        let mut selections = self.selections.all_adjusted(cx);
 9725        let buffer = self.buffer.read(cx);
 9726        let snapshot = buffer.snapshot(cx);
 9727        let rows_iter = selections.iter().map(|s| s.head().row);
 9728        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9729
 9730        let has_some_cursor_in_whitespace = selections
 9731            .iter()
 9732            .filter(|selection| selection.is_empty())
 9733            .any(|selection| {
 9734                let cursor = selection.head();
 9735                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9736                cursor.column < current_indent.len
 9737            });
 9738
 9739        let mut edits = Vec::new();
 9740        let mut prev_edited_row = 0;
 9741        let mut row_delta = 0;
 9742        for selection in &mut selections {
 9743            if selection.start.row != prev_edited_row {
 9744                row_delta = 0;
 9745            }
 9746            prev_edited_row = selection.end.row;
 9747
 9748            // If the selection is non-empty, then increase the indentation of the selected lines.
 9749            if !selection.is_empty() {
 9750                row_delta =
 9751                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9752                continue;
 9753            }
 9754
 9755            let cursor = selection.head();
 9756            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9757            if let Some(suggested_indent) =
 9758                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9759            {
 9760                // Don't do anything if already at suggested indent
 9761                // and there is any other cursor which is not
 9762                if has_some_cursor_in_whitespace
 9763                    && cursor.column == current_indent.len
 9764                    && current_indent.len == suggested_indent.len
 9765                {
 9766                    continue;
 9767                }
 9768
 9769                // Adjust line and move cursor to suggested indent
 9770                // if cursor is not at suggested indent
 9771                if cursor.column < suggested_indent.len
 9772                    && cursor.column <= current_indent.len
 9773                    && current_indent.len <= suggested_indent.len
 9774                {
 9775                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9776                    selection.end = selection.start;
 9777                    if row_delta == 0 {
 9778                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9779                            cursor.row,
 9780                            current_indent,
 9781                            suggested_indent,
 9782                        ));
 9783                        row_delta = suggested_indent.len - current_indent.len;
 9784                    }
 9785                    continue;
 9786                }
 9787
 9788                // If current indent is more than suggested indent
 9789                // only move cursor to current indent and skip indent
 9790                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9791                    selection.start = Point::new(cursor.row, current_indent.len);
 9792                    selection.end = selection.start;
 9793                    continue;
 9794                }
 9795            }
 9796
 9797            // Otherwise, insert a hard or soft tab.
 9798            let settings = buffer.language_settings_at(cursor, cx);
 9799            let tab_size = if settings.hard_tabs {
 9800                IndentSize::tab()
 9801            } else {
 9802                let tab_size = settings.tab_size.get();
 9803                let indent_remainder = snapshot
 9804                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9805                    .flat_map(str::chars)
 9806                    .fold(row_delta % tab_size, |counter: u32, c| {
 9807                        if c == '\t' {
 9808                            0
 9809                        } else {
 9810                            (counter + 1) % tab_size
 9811                        }
 9812                    });
 9813
 9814                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9815                IndentSize::spaces(chars_to_next_tab_stop)
 9816            };
 9817            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9818            selection.end = selection.start;
 9819            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9820            row_delta += tab_size.len;
 9821        }
 9822
 9823        self.transact(window, cx, |this, window, cx| {
 9824            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9825            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9826            this.refresh_inline_completion(true, false, window, cx);
 9827        });
 9828    }
 9829
 9830    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9831        if self.read_only(cx) {
 9832            return;
 9833        }
 9834        if self.mode.is_single_line() {
 9835            cx.propagate();
 9836            return;
 9837        }
 9838
 9839        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9840        let mut selections = self.selections.all::<Point>(cx);
 9841        let mut prev_edited_row = 0;
 9842        let mut row_delta = 0;
 9843        let mut edits = Vec::new();
 9844        let buffer = self.buffer.read(cx);
 9845        let snapshot = buffer.snapshot(cx);
 9846        for selection in &mut selections {
 9847            if selection.start.row != prev_edited_row {
 9848                row_delta = 0;
 9849            }
 9850            prev_edited_row = selection.end.row;
 9851
 9852            row_delta =
 9853                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9854        }
 9855
 9856        self.transact(window, cx, |this, window, cx| {
 9857            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9858            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9859        });
 9860    }
 9861
 9862    fn indent_selection(
 9863        buffer: &MultiBuffer,
 9864        snapshot: &MultiBufferSnapshot,
 9865        selection: &mut Selection<Point>,
 9866        edits: &mut Vec<(Range<Point>, String)>,
 9867        delta_for_start_row: u32,
 9868        cx: &App,
 9869    ) -> u32 {
 9870        let settings = buffer.language_settings_at(selection.start, cx);
 9871        let tab_size = settings.tab_size.get();
 9872        let indent_kind = if settings.hard_tabs {
 9873            IndentKind::Tab
 9874        } else {
 9875            IndentKind::Space
 9876        };
 9877        let mut start_row = selection.start.row;
 9878        let mut end_row = selection.end.row + 1;
 9879
 9880        // If a selection ends at the beginning of a line, don't indent
 9881        // that last line.
 9882        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9883            end_row -= 1;
 9884        }
 9885
 9886        // Avoid re-indenting a row that has already been indented by a
 9887        // previous selection, but still update this selection's column
 9888        // to reflect that indentation.
 9889        if delta_for_start_row > 0 {
 9890            start_row += 1;
 9891            selection.start.column += delta_for_start_row;
 9892            if selection.end.row == selection.start.row {
 9893                selection.end.column += delta_for_start_row;
 9894            }
 9895        }
 9896
 9897        let mut delta_for_end_row = 0;
 9898        let has_multiple_rows = start_row + 1 != end_row;
 9899        for row in start_row..end_row {
 9900            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9901            let indent_delta = match (current_indent.kind, indent_kind) {
 9902                (IndentKind::Space, IndentKind::Space) => {
 9903                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9904                    IndentSize::spaces(columns_to_next_tab_stop)
 9905                }
 9906                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9907                (_, IndentKind::Tab) => IndentSize::tab(),
 9908            };
 9909
 9910            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9911                0
 9912            } else {
 9913                selection.start.column
 9914            };
 9915            let row_start = Point::new(row, start);
 9916            edits.push((
 9917                row_start..row_start,
 9918                indent_delta.chars().collect::<String>(),
 9919            ));
 9920
 9921            // Update this selection's endpoints to reflect the indentation.
 9922            if row == selection.start.row {
 9923                selection.start.column += indent_delta.len;
 9924            }
 9925            if row == selection.end.row {
 9926                selection.end.column += indent_delta.len;
 9927                delta_for_end_row = indent_delta.len;
 9928            }
 9929        }
 9930
 9931        if selection.start.row == selection.end.row {
 9932            delta_for_start_row + delta_for_end_row
 9933        } else {
 9934            delta_for_end_row
 9935        }
 9936    }
 9937
 9938    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9939        if self.read_only(cx) {
 9940            return;
 9941        }
 9942        if self.mode.is_single_line() {
 9943            cx.propagate();
 9944            return;
 9945        }
 9946
 9947        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9948        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9949        let selections = self.selections.all::<Point>(cx);
 9950        let mut deletion_ranges = Vec::new();
 9951        let mut last_outdent = None;
 9952        {
 9953            let buffer = self.buffer.read(cx);
 9954            let snapshot = buffer.snapshot(cx);
 9955            for selection in &selections {
 9956                let settings = buffer.language_settings_at(selection.start, cx);
 9957                let tab_size = settings.tab_size.get();
 9958                let mut rows = selection.spanned_rows(false, &display_map);
 9959
 9960                // Avoid re-outdenting a row that has already been outdented by a
 9961                // previous selection.
 9962                if let Some(last_row) = last_outdent {
 9963                    if last_row == rows.start {
 9964                        rows.start = rows.start.next_row();
 9965                    }
 9966                }
 9967                let has_multiple_rows = rows.len() > 1;
 9968                for row in rows.iter_rows() {
 9969                    let indent_size = snapshot.indent_size_for_line(row);
 9970                    if indent_size.len > 0 {
 9971                        let deletion_len = match indent_size.kind {
 9972                            IndentKind::Space => {
 9973                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9974                                if columns_to_prev_tab_stop == 0 {
 9975                                    tab_size
 9976                                } else {
 9977                                    columns_to_prev_tab_stop
 9978                                }
 9979                            }
 9980                            IndentKind::Tab => 1,
 9981                        };
 9982                        let start = if has_multiple_rows
 9983                            || deletion_len > selection.start.column
 9984                            || indent_size.len < selection.start.column
 9985                        {
 9986                            0
 9987                        } else {
 9988                            selection.start.column - deletion_len
 9989                        };
 9990                        deletion_ranges.push(
 9991                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9992                        );
 9993                        last_outdent = Some(row);
 9994                    }
 9995                }
 9996            }
 9997        }
 9998
 9999        self.transact(window, cx, |this, window, cx| {
10000            this.buffer.update(cx, |buffer, cx| {
10001                let empty_str: Arc<str> = Arc::default();
10002                buffer.edit(
10003                    deletion_ranges
10004                        .into_iter()
10005                        .map(|range| (range, empty_str.clone())),
10006                    None,
10007                    cx,
10008                );
10009            });
10010            let selections = this.selections.all::<usize>(cx);
10011            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10012        });
10013    }
10014
10015    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10016        if self.read_only(cx) {
10017            return;
10018        }
10019        if self.mode.is_single_line() {
10020            cx.propagate();
10021            return;
10022        }
10023
10024        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10025        let selections = self
10026            .selections
10027            .all::<usize>(cx)
10028            .into_iter()
10029            .map(|s| s.range());
10030
10031        self.transact(window, cx, |this, window, cx| {
10032            this.buffer.update(cx, |buffer, cx| {
10033                buffer.autoindent_ranges(selections, cx);
10034            });
10035            let selections = this.selections.all::<usize>(cx);
10036            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10037        });
10038    }
10039
10040    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10042        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10043        let selections = self.selections.all::<Point>(cx);
10044
10045        let mut new_cursors = Vec::new();
10046        let mut edit_ranges = Vec::new();
10047        let mut selections = selections.iter().peekable();
10048        while let Some(selection) = selections.next() {
10049            let mut rows = selection.spanned_rows(false, &display_map);
10050            let goal_display_column = selection.head().to_display_point(&display_map).column();
10051
10052            // Accumulate contiguous regions of rows that we want to delete.
10053            while let Some(next_selection) = selections.peek() {
10054                let next_rows = next_selection.spanned_rows(false, &display_map);
10055                if next_rows.start <= rows.end {
10056                    rows.end = next_rows.end;
10057                    selections.next().unwrap();
10058                } else {
10059                    break;
10060                }
10061            }
10062
10063            let buffer = &display_map.buffer_snapshot;
10064            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10065            let edit_end;
10066            let cursor_buffer_row;
10067            if buffer.max_point().row >= rows.end.0 {
10068                // If there's a line after the range, delete the \n from the end of the row range
10069                // and position the cursor on the next line.
10070                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10071                cursor_buffer_row = rows.end;
10072            } else {
10073                // If there isn't a line after the range, delete the \n from the line before the
10074                // start of the row range and position the cursor there.
10075                edit_start = edit_start.saturating_sub(1);
10076                edit_end = buffer.len();
10077                cursor_buffer_row = rows.start.previous_row();
10078            }
10079
10080            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10081            *cursor.column_mut() =
10082                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10083
10084            new_cursors.push((
10085                selection.id,
10086                buffer.anchor_after(cursor.to_point(&display_map)),
10087            ));
10088            edit_ranges.push(edit_start..edit_end);
10089        }
10090
10091        self.transact(window, cx, |this, window, cx| {
10092            let buffer = this.buffer.update(cx, |buffer, cx| {
10093                let empty_str: Arc<str> = Arc::default();
10094                buffer.edit(
10095                    edit_ranges
10096                        .into_iter()
10097                        .map(|range| (range, empty_str.clone())),
10098                    None,
10099                    cx,
10100                );
10101                buffer.snapshot(cx)
10102            });
10103            let new_selections = new_cursors
10104                .into_iter()
10105                .map(|(id, cursor)| {
10106                    let cursor = cursor.to_point(&buffer);
10107                    Selection {
10108                        id,
10109                        start: cursor,
10110                        end: cursor,
10111                        reversed: false,
10112                        goal: SelectionGoal::None,
10113                    }
10114                })
10115                .collect();
10116
10117            this.change_selections(Default::default(), window, cx, |s| {
10118                s.select(new_selections);
10119            });
10120        });
10121    }
10122
10123    pub fn join_lines_impl(
10124        &mut self,
10125        insert_whitespace: bool,
10126        window: &mut Window,
10127        cx: &mut Context<Self>,
10128    ) {
10129        if self.read_only(cx) {
10130            return;
10131        }
10132        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10133        for selection in self.selections.all::<Point>(cx) {
10134            let start = MultiBufferRow(selection.start.row);
10135            // Treat single line selections as if they include the next line. Otherwise this action
10136            // would do nothing for single line selections individual cursors.
10137            let end = if selection.start.row == selection.end.row {
10138                MultiBufferRow(selection.start.row + 1)
10139            } else {
10140                MultiBufferRow(selection.end.row)
10141            };
10142
10143            if let Some(last_row_range) = row_ranges.last_mut() {
10144                if start <= last_row_range.end {
10145                    last_row_range.end = end;
10146                    continue;
10147                }
10148            }
10149            row_ranges.push(start..end);
10150        }
10151
10152        let snapshot = self.buffer.read(cx).snapshot(cx);
10153        let mut cursor_positions = Vec::new();
10154        for row_range in &row_ranges {
10155            let anchor = snapshot.anchor_before(Point::new(
10156                row_range.end.previous_row().0,
10157                snapshot.line_len(row_range.end.previous_row()),
10158            ));
10159            cursor_positions.push(anchor..anchor);
10160        }
10161
10162        self.transact(window, cx, |this, window, cx| {
10163            for row_range in row_ranges.into_iter().rev() {
10164                for row in row_range.iter_rows().rev() {
10165                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10166                    let next_line_row = row.next_row();
10167                    let indent = snapshot.indent_size_for_line(next_line_row);
10168                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10169
10170                    let replace =
10171                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10172                            " "
10173                        } else {
10174                            ""
10175                        };
10176
10177                    this.buffer.update(cx, |buffer, cx| {
10178                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10179                    });
10180                }
10181            }
10182
10183            this.change_selections(Default::default(), window, cx, |s| {
10184                s.select_anchor_ranges(cursor_positions)
10185            });
10186        });
10187    }
10188
10189    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10190        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10191        self.join_lines_impl(true, window, cx);
10192    }
10193
10194    pub fn sort_lines_case_sensitive(
10195        &mut self,
10196        _: &SortLinesCaseSensitive,
10197        window: &mut Window,
10198        cx: &mut Context<Self>,
10199    ) {
10200        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10201    }
10202
10203    pub fn sort_lines_case_insensitive(
10204        &mut self,
10205        _: &SortLinesCaseInsensitive,
10206        window: &mut Window,
10207        cx: &mut Context<Self>,
10208    ) {
10209        self.manipulate_immutable_lines(window, cx, |lines| {
10210            lines.sort_by_key(|line| line.to_lowercase())
10211        })
10212    }
10213
10214    pub fn unique_lines_case_insensitive(
10215        &mut self,
10216        _: &UniqueLinesCaseInsensitive,
10217        window: &mut Window,
10218        cx: &mut Context<Self>,
10219    ) {
10220        self.manipulate_immutable_lines(window, cx, |lines| {
10221            let mut seen = HashSet::default();
10222            lines.retain(|line| seen.insert(line.to_lowercase()));
10223        })
10224    }
10225
10226    pub fn unique_lines_case_sensitive(
10227        &mut self,
10228        _: &UniqueLinesCaseSensitive,
10229        window: &mut Window,
10230        cx: &mut Context<Self>,
10231    ) {
10232        self.manipulate_immutable_lines(window, cx, |lines| {
10233            let mut seen = HashSet::default();
10234            lines.retain(|line| seen.insert(*line));
10235        })
10236    }
10237
10238    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10239        let Some(project) = self.project.clone() else {
10240            return;
10241        };
10242        self.reload(project, window, cx)
10243            .detach_and_notify_err(window, cx);
10244    }
10245
10246    pub fn restore_file(
10247        &mut self,
10248        _: &::git::RestoreFile,
10249        window: &mut Window,
10250        cx: &mut Context<Self>,
10251    ) {
10252        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10253        let mut buffer_ids = HashSet::default();
10254        let snapshot = self.buffer().read(cx).snapshot(cx);
10255        for selection in self.selections.all::<usize>(cx) {
10256            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10257        }
10258
10259        let buffer = self.buffer().read(cx);
10260        let ranges = buffer_ids
10261            .into_iter()
10262            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10263            .collect::<Vec<_>>();
10264
10265        self.restore_hunks_in_ranges(ranges, window, cx);
10266    }
10267
10268    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10269        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10270        let selections = self
10271            .selections
10272            .all(cx)
10273            .into_iter()
10274            .map(|s| s.range())
10275            .collect();
10276        self.restore_hunks_in_ranges(selections, window, cx);
10277    }
10278
10279    pub fn restore_hunks_in_ranges(
10280        &mut self,
10281        ranges: Vec<Range<Point>>,
10282        window: &mut Window,
10283        cx: &mut Context<Editor>,
10284    ) {
10285        let mut revert_changes = HashMap::default();
10286        let chunk_by = self
10287            .snapshot(window, cx)
10288            .hunks_for_ranges(ranges)
10289            .into_iter()
10290            .chunk_by(|hunk| hunk.buffer_id);
10291        for (buffer_id, hunks) in &chunk_by {
10292            let hunks = hunks.collect::<Vec<_>>();
10293            for hunk in &hunks {
10294                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10295            }
10296            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10297        }
10298        drop(chunk_by);
10299        if !revert_changes.is_empty() {
10300            self.transact(window, cx, |editor, window, cx| {
10301                editor.restore(revert_changes, window, cx);
10302            });
10303        }
10304    }
10305
10306    pub fn open_active_item_in_terminal(
10307        &mut self,
10308        _: &OpenInTerminal,
10309        window: &mut Window,
10310        cx: &mut Context<Self>,
10311    ) {
10312        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10313            let project_path = buffer.read(cx).project_path(cx)?;
10314            let project = self.project.as_ref()?.read(cx);
10315            let entry = project.entry_for_path(&project_path, cx)?;
10316            let parent = match &entry.canonical_path {
10317                Some(canonical_path) => canonical_path.to_path_buf(),
10318                None => project.absolute_path(&project_path, cx)?,
10319            }
10320            .parent()?
10321            .to_path_buf();
10322            Some(parent)
10323        }) {
10324            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10325        }
10326    }
10327
10328    fn set_breakpoint_context_menu(
10329        &mut self,
10330        display_row: DisplayRow,
10331        position: Option<Anchor>,
10332        clicked_point: gpui::Point<Pixels>,
10333        window: &mut Window,
10334        cx: &mut Context<Self>,
10335    ) {
10336        let source = self
10337            .buffer
10338            .read(cx)
10339            .snapshot(cx)
10340            .anchor_before(Point::new(display_row.0, 0u32));
10341
10342        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10343
10344        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10345            self,
10346            source,
10347            clicked_point,
10348            context_menu,
10349            window,
10350            cx,
10351        );
10352    }
10353
10354    fn add_edit_breakpoint_block(
10355        &mut self,
10356        anchor: Anchor,
10357        breakpoint: &Breakpoint,
10358        edit_action: BreakpointPromptEditAction,
10359        window: &mut Window,
10360        cx: &mut Context<Self>,
10361    ) {
10362        let weak_editor = cx.weak_entity();
10363        let bp_prompt = cx.new(|cx| {
10364            BreakpointPromptEditor::new(
10365                weak_editor,
10366                anchor,
10367                breakpoint.clone(),
10368                edit_action,
10369                window,
10370                cx,
10371            )
10372        });
10373
10374        let height = bp_prompt.update(cx, |this, cx| {
10375            this.prompt
10376                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10377        });
10378        let cloned_prompt = bp_prompt.clone();
10379        let blocks = vec![BlockProperties {
10380            style: BlockStyle::Sticky,
10381            placement: BlockPlacement::Above(anchor),
10382            height: Some(height),
10383            render: Arc::new(move |cx| {
10384                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10385                cloned_prompt.clone().into_any_element()
10386            }),
10387            priority: 0,
10388            render_in_minimap: true,
10389        }];
10390
10391        let focus_handle = bp_prompt.focus_handle(cx);
10392        window.focus(&focus_handle);
10393
10394        let block_ids = self.insert_blocks(blocks, None, cx);
10395        bp_prompt.update(cx, |prompt, _| {
10396            prompt.add_block_ids(block_ids);
10397        });
10398    }
10399
10400    pub(crate) fn breakpoint_at_row(
10401        &self,
10402        row: u32,
10403        window: &mut Window,
10404        cx: &mut Context<Self>,
10405    ) -> Option<(Anchor, Breakpoint)> {
10406        let snapshot = self.snapshot(window, cx);
10407        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10408
10409        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10410    }
10411
10412    pub(crate) fn breakpoint_at_anchor(
10413        &self,
10414        breakpoint_position: Anchor,
10415        snapshot: &EditorSnapshot,
10416        cx: &mut Context<Self>,
10417    ) -> Option<(Anchor, Breakpoint)> {
10418        let project = self.project.clone()?;
10419
10420        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10421            snapshot
10422                .buffer_snapshot
10423                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10424        })?;
10425
10426        let enclosing_excerpt = breakpoint_position.excerpt_id;
10427        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10428        let buffer_snapshot = buffer.read(cx).snapshot();
10429
10430        let row = buffer_snapshot
10431            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10432            .row;
10433
10434        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10435        let anchor_end = snapshot
10436            .buffer_snapshot
10437            .anchor_after(Point::new(row, line_len));
10438
10439        let bp = self
10440            .breakpoint_store
10441            .as_ref()?
10442            .read_with(cx, |breakpoint_store, cx| {
10443                breakpoint_store
10444                    .breakpoints(
10445                        &buffer,
10446                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10447                        &buffer_snapshot,
10448                        cx,
10449                    )
10450                    .next()
10451                    .and_then(|(bp, _)| {
10452                        let breakpoint_row = buffer_snapshot
10453                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10454                            .row;
10455
10456                        if breakpoint_row == row {
10457                            snapshot
10458                                .buffer_snapshot
10459                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10460                                .map(|position| (position, bp.bp.clone()))
10461                        } else {
10462                            None
10463                        }
10464                    })
10465            });
10466        bp
10467    }
10468
10469    pub fn edit_log_breakpoint(
10470        &mut self,
10471        _: &EditLogBreakpoint,
10472        window: &mut Window,
10473        cx: &mut Context<Self>,
10474    ) {
10475        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10476            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10477                message: None,
10478                state: BreakpointState::Enabled,
10479                condition: None,
10480                hit_condition: None,
10481            });
10482
10483            self.add_edit_breakpoint_block(
10484                anchor,
10485                &breakpoint,
10486                BreakpointPromptEditAction::Log,
10487                window,
10488                cx,
10489            );
10490        }
10491    }
10492
10493    fn breakpoints_at_cursors(
10494        &self,
10495        window: &mut Window,
10496        cx: &mut Context<Self>,
10497    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10498        let snapshot = self.snapshot(window, cx);
10499        let cursors = self
10500            .selections
10501            .disjoint_anchors()
10502            .into_iter()
10503            .map(|selection| {
10504                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10505
10506                let breakpoint_position = self
10507                    .breakpoint_at_row(cursor_position.row, window, cx)
10508                    .map(|bp| bp.0)
10509                    .unwrap_or_else(|| {
10510                        snapshot
10511                            .display_snapshot
10512                            .buffer_snapshot
10513                            .anchor_after(Point::new(cursor_position.row, 0))
10514                    });
10515
10516                let breakpoint = self
10517                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10518                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10519
10520                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10521            })
10522            // 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.
10523            .collect::<HashMap<Anchor, _>>();
10524
10525        cursors.into_iter().collect()
10526    }
10527
10528    pub fn enable_breakpoint(
10529        &mut self,
10530        _: &crate::actions::EnableBreakpoint,
10531        window: &mut Window,
10532        cx: &mut Context<Self>,
10533    ) {
10534        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10535            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10536                continue;
10537            };
10538            self.edit_breakpoint_at_anchor(
10539                anchor,
10540                breakpoint,
10541                BreakpointEditAction::InvertState,
10542                cx,
10543            );
10544        }
10545    }
10546
10547    pub fn disable_breakpoint(
10548        &mut self,
10549        _: &crate::actions::DisableBreakpoint,
10550        window: &mut Window,
10551        cx: &mut Context<Self>,
10552    ) {
10553        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10554            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10555                continue;
10556            };
10557            self.edit_breakpoint_at_anchor(
10558                anchor,
10559                breakpoint,
10560                BreakpointEditAction::InvertState,
10561                cx,
10562            );
10563        }
10564    }
10565
10566    pub fn toggle_breakpoint(
10567        &mut self,
10568        _: &crate::actions::ToggleBreakpoint,
10569        window: &mut Window,
10570        cx: &mut Context<Self>,
10571    ) {
10572        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10573            if let Some(breakpoint) = breakpoint {
10574                self.edit_breakpoint_at_anchor(
10575                    anchor,
10576                    breakpoint,
10577                    BreakpointEditAction::Toggle,
10578                    cx,
10579                );
10580            } else {
10581                self.edit_breakpoint_at_anchor(
10582                    anchor,
10583                    Breakpoint::new_standard(),
10584                    BreakpointEditAction::Toggle,
10585                    cx,
10586                );
10587            }
10588        }
10589    }
10590
10591    pub fn edit_breakpoint_at_anchor(
10592        &mut self,
10593        breakpoint_position: Anchor,
10594        breakpoint: Breakpoint,
10595        edit_action: BreakpointEditAction,
10596        cx: &mut Context<Self>,
10597    ) {
10598        let Some(breakpoint_store) = &self.breakpoint_store else {
10599            return;
10600        };
10601
10602        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10603            if breakpoint_position == Anchor::min() {
10604                self.buffer()
10605                    .read(cx)
10606                    .excerpt_buffer_ids()
10607                    .into_iter()
10608                    .next()
10609            } else {
10610                None
10611            }
10612        }) else {
10613            return;
10614        };
10615
10616        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10617            return;
10618        };
10619
10620        breakpoint_store.update(cx, |breakpoint_store, cx| {
10621            breakpoint_store.toggle_breakpoint(
10622                buffer,
10623                BreakpointWithPosition {
10624                    position: breakpoint_position.text_anchor,
10625                    bp: breakpoint,
10626                },
10627                edit_action,
10628                cx,
10629            );
10630        });
10631
10632        cx.notify();
10633    }
10634
10635    #[cfg(any(test, feature = "test-support"))]
10636    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10637        self.breakpoint_store.clone()
10638    }
10639
10640    pub fn prepare_restore_change(
10641        &self,
10642        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10643        hunk: &MultiBufferDiffHunk,
10644        cx: &mut App,
10645    ) -> Option<()> {
10646        if hunk.is_created_file() {
10647            return None;
10648        }
10649        let buffer = self.buffer.read(cx);
10650        let diff = buffer.diff_for(hunk.buffer_id)?;
10651        let buffer = buffer.buffer(hunk.buffer_id)?;
10652        let buffer = buffer.read(cx);
10653        let original_text = diff
10654            .read(cx)
10655            .base_text()
10656            .as_rope()
10657            .slice(hunk.diff_base_byte_range.clone());
10658        let buffer_snapshot = buffer.snapshot();
10659        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10660        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10661            probe
10662                .0
10663                .start
10664                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10665                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10666        }) {
10667            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10668            Some(())
10669        } else {
10670            None
10671        }
10672    }
10673
10674    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10675        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10676    }
10677
10678    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10679        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10680    }
10681
10682    fn manipulate_lines<M>(
10683        &mut self,
10684        window: &mut Window,
10685        cx: &mut Context<Self>,
10686        mut manipulate: M,
10687    ) where
10688        M: FnMut(&str) -> LineManipulationResult,
10689    {
10690        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10691
10692        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10693        let buffer = self.buffer.read(cx).snapshot(cx);
10694
10695        let mut edits = Vec::new();
10696
10697        let selections = self.selections.all::<Point>(cx);
10698        let mut selections = selections.iter().peekable();
10699        let mut contiguous_row_selections = Vec::new();
10700        let mut new_selections = Vec::new();
10701        let mut added_lines = 0;
10702        let mut removed_lines = 0;
10703
10704        while let Some(selection) = selections.next() {
10705            let (start_row, end_row) = consume_contiguous_rows(
10706                &mut contiguous_row_selections,
10707                selection,
10708                &display_map,
10709                &mut selections,
10710            );
10711
10712            let start_point = Point::new(start_row.0, 0);
10713            let end_point = Point::new(
10714                end_row.previous_row().0,
10715                buffer.line_len(end_row.previous_row()),
10716            );
10717            let text = buffer
10718                .text_for_range(start_point..end_point)
10719                .collect::<String>();
10720
10721            let LineManipulationResult {
10722                new_text,
10723                line_count_before,
10724                line_count_after,
10725            } = manipulate(&text);
10726
10727            edits.push((start_point..end_point, new_text));
10728
10729            // Selections must change based on added and removed line count
10730            let start_row =
10731                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10732            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10733            new_selections.push(Selection {
10734                id: selection.id,
10735                start: start_row,
10736                end: end_row,
10737                goal: SelectionGoal::None,
10738                reversed: selection.reversed,
10739            });
10740
10741            if line_count_after > line_count_before {
10742                added_lines += line_count_after - line_count_before;
10743            } else if line_count_before > line_count_after {
10744                removed_lines += line_count_before - line_count_after;
10745            }
10746        }
10747
10748        self.transact(window, cx, |this, window, cx| {
10749            let buffer = this.buffer.update(cx, |buffer, cx| {
10750                buffer.edit(edits, None, cx);
10751                buffer.snapshot(cx)
10752            });
10753
10754            // Recalculate offsets on newly edited buffer
10755            let new_selections = new_selections
10756                .iter()
10757                .map(|s| {
10758                    let start_point = Point::new(s.start.0, 0);
10759                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10760                    Selection {
10761                        id: s.id,
10762                        start: buffer.point_to_offset(start_point),
10763                        end: buffer.point_to_offset(end_point),
10764                        goal: s.goal,
10765                        reversed: s.reversed,
10766                    }
10767                })
10768                .collect();
10769
10770            this.change_selections(Default::default(), window, cx, |s| {
10771                s.select(new_selections);
10772            });
10773
10774            this.request_autoscroll(Autoscroll::fit(), cx);
10775        });
10776    }
10777
10778    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10779        self.manipulate_text(window, cx, |text| {
10780            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10781            if has_upper_case_characters {
10782                text.to_lowercase()
10783            } else {
10784                text.to_uppercase()
10785            }
10786        })
10787    }
10788
10789    fn manipulate_immutable_lines<Fn>(
10790        &mut self,
10791        window: &mut Window,
10792        cx: &mut Context<Self>,
10793        mut callback: Fn,
10794    ) where
10795        Fn: FnMut(&mut Vec<&str>),
10796    {
10797        self.manipulate_lines(window, cx, |text| {
10798            let mut lines: Vec<&str> = text.split('\n').collect();
10799            let line_count_before = lines.len();
10800
10801            callback(&mut lines);
10802
10803            LineManipulationResult {
10804                new_text: lines.join("\n"),
10805                line_count_before,
10806                line_count_after: lines.len(),
10807            }
10808        });
10809    }
10810
10811    fn manipulate_mutable_lines<Fn>(
10812        &mut self,
10813        window: &mut Window,
10814        cx: &mut Context<Self>,
10815        mut callback: Fn,
10816    ) where
10817        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10818    {
10819        self.manipulate_lines(window, cx, |text| {
10820            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10821            let line_count_before = lines.len();
10822
10823            callback(&mut lines);
10824
10825            LineManipulationResult {
10826                new_text: lines.join("\n"),
10827                line_count_before,
10828                line_count_after: lines.len(),
10829            }
10830        });
10831    }
10832
10833    pub fn convert_indentation_to_spaces(
10834        &mut self,
10835        _: &ConvertIndentationToSpaces,
10836        window: &mut Window,
10837        cx: &mut Context<Self>,
10838    ) {
10839        let settings = self.buffer.read(cx).language_settings(cx);
10840        let tab_size = settings.tab_size.get() as usize;
10841
10842        self.manipulate_mutable_lines(window, cx, |lines| {
10843            // Allocates a reasonably sized scratch buffer once for the whole loop
10844            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10845            // Avoids recomputing spaces that could be inserted many times
10846            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10847                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10848                .collect();
10849
10850            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10851                let mut chars = line.as_ref().chars();
10852                let mut col = 0;
10853                let mut changed = false;
10854
10855                while let Some(ch) = chars.next() {
10856                    match ch {
10857                        ' ' => {
10858                            reindented_line.push(' ');
10859                            col += 1;
10860                        }
10861                        '\t' => {
10862                            // \t are converted to spaces depending on the current column
10863                            let spaces_len = tab_size - (col % tab_size);
10864                            reindented_line.extend(&space_cache[spaces_len - 1]);
10865                            col += spaces_len;
10866                            changed = true;
10867                        }
10868                        _ => {
10869                            // If we dont append before break, the character is consumed
10870                            reindented_line.push(ch);
10871                            break;
10872                        }
10873                    }
10874                }
10875
10876                if !changed {
10877                    reindented_line.clear();
10878                    continue;
10879                }
10880                // Append the rest of the line and replace old reference with new one
10881                reindented_line.extend(chars);
10882                *line = Cow::Owned(reindented_line.clone());
10883                reindented_line.clear();
10884            }
10885        });
10886    }
10887
10888    pub fn convert_indentation_to_tabs(
10889        &mut self,
10890        _: &ConvertIndentationToTabs,
10891        window: &mut Window,
10892        cx: &mut Context<Self>,
10893    ) {
10894        let settings = self.buffer.read(cx).language_settings(cx);
10895        let tab_size = settings.tab_size.get() as usize;
10896
10897        self.manipulate_mutable_lines(window, cx, |lines| {
10898            // Allocates a reasonably sized buffer once for the whole loop
10899            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10900            // Avoids recomputing spaces that could be inserted many times
10901            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10902                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10903                .collect();
10904
10905            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10906                let mut chars = line.chars();
10907                let mut spaces_count = 0;
10908                let mut first_non_indent_char = None;
10909                let mut changed = false;
10910
10911                while let Some(ch) = chars.next() {
10912                    match ch {
10913                        ' ' => {
10914                            // Keep track of spaces. Append \t when we reach tab_size
10915                            spaces_count += 1;
10916                            changed = true;
10917                            if spaces_count == tab_size {
10918                                reindented_line.push('\t');
10919                                spaces_count = 0;
10920                            }
10921                        }
10922                        '\t' => {
10923                            reindented_line.push('\t');
10924                            spaces_count = 0;
10925                        }
10926                        _ => {
10927                            // Dont append it yet, we might have remaining spaces
10928                            first_non_indent_char = Some(ch);
10929                            break;
10930                        }
10931                    }
10932                }
10933
10934                if !changed {
10935                    reindented_line.clear();
10936                    continue;
10937                }
10938                // Remaining spaces that didn't make a full tab stop
10939                if spaces_count > 0 {
10940                    reindented_line.extend(&space_cache[spaces_count - 1]);
10941                }
10942                // If we consume an extra character that was not indentation, add it back
10943                if let Some(extra_char) = first_non_indent_char {
10944                    reindented_line.push(extra_char);
10945                }
10946                // Append the rest of the line and replace old reference with new one
10947                reindented_line.extend(chars);
10948                *line = Cow::Owned(reindented_line.clone());
10949                reindented_line.clear();
10950            }
10951        });
10952    }
10953
10954    pub fn convert_to_upper_case(
10955        &mut self,
10956        _: &ConvertToUpperCase,
10957        window: &mut Window,
10958        cx: &mut Context<Self>,
10959    ) {
10960        self.manipulate_text(window, cx, |text| text.to_uppercase())
10961    }
10962
10963    pub fn convert_to_lower_case(
10964        &mut self,
10965        _: &ConvertToLowerCase,
10966        window: &mut Window,
10967        cx: &mut Context<Self>,
10968    ) {
10969        self.manipulate_text(window, cx, |text| text.to_lowercase())
10970    }
10971
10972    pub fn convert_to_title_case(
10973        &mut self,
10974        _: &ConvertToTitleCase,
10975        window: &mut Window,
10976        cx: &mut Context<Self>,
10977    ) {
10978        self.manipulate_text(window, cx, |text| {
10979            text.split('\n')
10980                .map(|line| line.to_case(Case::Title))
10981                .join("\n")
10982        })
10983    }
10984
10985    pub fn convert_to_snake_case(
10986        &mut self,
10987        _: &ConvertToSnakeCase,
10988        window: &mut Window,
10989        cx: &mut Context<Self>,
10990    ) {
10991        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10992    }
10993
10994    pub fn convert_to_kebab_case(
10995        &mut self,
10996        _: &ConvertToKebabCase,
10997        window: &mut Window,
10998        cx: &mut Context<Self>,
10999    ) {
11000        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11001    }
11002
11003    pub fn convert_to_upper_camel_case(
11004        &mut self,
11005        _: &ConvertToUpperCamelCase,
11006        window: &mut Window,
11007        cx: &mut Context<Self>,
11008    ) {
11009        self.manipulate_text(window, cx, |text| {
11010            text.split('\n')
11011                .map(|line| line.to_case(Case::UpperCamel))
11012                .join("\n")
11013        })
11014    }
11015
11016    pub fn convert_to_lower_camel_case(
11017        &mut self,
11018        _: &ConvertToLowerCamelCase,
11019        window: &mut Window,
11020        cx: &mut Context<Self>,
11021    ) {
11022        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11023    }
11024
11025    pub fn convert_to_opposite_case(
11026        &mut self,
11027        _: &ConvertToOppositeCase,
11028        window: &mut Window,
11029        cx: &mut Context<Self>,
11030    ) {
11031        self.manipulate_text(window, cx, |text| {
11032            text.chars()
11033                .fold(String::with_capacity(text.len()), |mut t, c| {
11034                    if c.is_uppercase() {
11035                        t.extend(c.to_lowercase());
11036                    } else {
11037                        t.extend(c.to_uppercase());
11038                    }
11039                    t
11040                })
11041        })
11042    }
11043
11044    pub fn convert_to_rot13(
11045        &mut self,
11046        _: &ConvertToRot13,
11047        window: &mut Window,
11048        cx: &mut Context<Self>,
11049    ) {
11050        self.manipulate_text(window, cx, |text| {
11051            text.chars()
11052                .map(|c| match c {
11053                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11054                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11055                    _ => c,
11056                })
11057                .collect()
11058        })
11059    }
11060
11061    pub fn convert_to_rot47(
11062        &mut self,
11063        _: &ConvertToRot47,
11064        window: &mut Window,
11065        cx: &mut Context<Self>,
11066    ) {
11067        self.manipulate_text(window, cx, |text| {
11068            text.chars()
11069                .map(|c| {
11070                    let code_point = c as u32;
11071                    if code_point >= 33 && code_point <= 126 {
11072                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11073                    }
11074                    c
11075                })
11076                .collect()
11077        })
11078    }
11079
11080    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11081    where
11082        Fn: FnMut(&str) -> String,
11083    {
11084        let buffer = self.buffer.read(cx).snapshot(cx);
11085
11086        let mut new_selections = Vec::new();
11087        let mut edits = Vec::new();
11088        let mut selection_adjustment = 0i32;
11089
11090        for selection in self.selections.all::<usize>(cx) {
11091            let selection_is_empty = selection.is_empty();
11092
11093            let (start, end) = if selection_is_empty {
11094                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11095                (word_range.start, word_range.end)
11096            } else {
11097                (selection.start, selection.end)
11098            };
11099
11100            let text = buffer.text_for_range(start..end).collect::<String>();
11101            let old_length = text.len() as i32;
11102            let text = callback(&text);
11103
11104            new_selections.push(Selection {
11105                start: (start as i32 - selection_adjustment) as usize,
11106                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11107                goal: SelectionGoal::None,
11108                ..selection
11109            });
11110
11111            selection_adjustment += old_length - text.len() as i32;
11112
11113            edits.push((start..end, text));
11114        }
11115
11116        self.transact(window, cx, |this, window, cx| {
11117            this.buffer.update(cx, |buffer, cx| {
11118                buffer.edit(edits, None, cx);
11119            });
11120
11121            this.change_selections(Default::default(), window, cx, |s| {
11122                s.select(new_selections);
11123            });
11124
11125            this.request_autoscroll(Autoscroll::fit(), cx);
11126        });
11127    }
11128
11129    pub fn move_selection_on_drop(
11130        &mut self,
11131        selection: &Selection<Anchor>,
11132        target: DisplayPoint,
11133        is_cut: bool,
11134        window: &mut Window,
11135        cx: &mut Context<Self>,
11136    ) {
11137        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11138        let buffer = &display_map.buffer_snapshot;
11139        let mut edits = Vec::new();
11140        let insert_point = display_map
11141            .clip_point(target, Bias::Left)
11142            .to_point(&display_map);
11143        let text = buffer
11144            .text_for_range(selection.start..selection.end)
11145            .collect::<String>();
11146        if is_cut {
11147            edits.push(((selection.start..selection.end), String::new()));
11148        }
11149        let insert_anchor = buffer.anchor_before(insert_point);
11150        edits.push(((insert_anchor..insert_anchor), text));
11151        let last_edit_start = insert_anchor.bias_left(buffer);
11152        let last_edit_end = insert_anchor.bias_right(buffer);
11153        self.transact(window, cx, |this, window, cx| {
11154            this.buffer.update(cx, |buffer, cx| {
11155                buffer.edit(edits, None, cx);
11156            });
11157            this.change_selections(Default::default(), window, cx, |s| {
11158                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11159            });
11160        });
11161    }
11162
11163    pub fn clear_selection_drag_state(&mut self) {
11164        self.selection_drag_state = SelectionDragState::None;
11165    }
11166
11167    pub fn duplicate(
11168        &mut self,
11169        upwards: bool,
11170        whole_lines: bool,
11171        window: &mut Window,
11172        cx: &mut Context<Self>,
11173    ) {
11174        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11175
11176        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11177        let buffer = &display_map.buffer_snapshot;
11178        let selections = self.selections.all::<Point>(cx);
11179
11180        let mut edits = Vec::new();
11181        let mut selections_iter = selections.iter().peekable();
11182        while let Some(selection) = selections_iter.next() {
11183            let mut rows = selection.spanned_rows(false, &display_map);
11184            // duplicate line-wise
11185            if whole_lines || selection.start == selection.end {
11186                // Avoid duplicating the same lines twice.
11187                while let Some(next_selection) = selections_iter.peek() {
11188                    let next_rows = next_selection.spanned_rows(false, &display_map);
11189                    if next_rows.start < rows.end {
11190                        rows.end = next_rows.end;
11191                        selections_iter.next().unwrap();
11192                    } else {
11193                        break;
11194                    }
11195                }
11196
11197                // Copy the text from the selected row region and splice it either at the start
11198                // or end of the region.
11199                let start = Point::new(rows.start.0, 0);
11200                let end = Point::new(
11201                    rows.end.previous_row().0,
11202                    buffer.line_len(rows.end.previous_row()),
11203                );
11204                let text = buffer
11205                    .text_for_range(start..end)
11206                    .chain(Some("\n"))
11207                    .collect::<String>();
11208                let insert_location = if upwards {
11209                    Point::new(rows.end.0, 0)
11210                } else {
11211                    start
11212                };
11213                edits.push((insert_location..insert_location, text));
11214            } else {
11215                // duplicate character-wise
11216                let start = selection.start;
11217                let end = selection.end;
11218                let text = buffer.text_for_range(start..end).collect::<String>();
11219                edits.push((selection.end..selection.end, text));
11220            }
11221        }
11222
11223        self.transact(window, cx, |this, _, cx| {
11224            this.buffer.update(cx, |buffer, cx| {
11225                buffer.edit(edits, None, cx);
11226            });
11227
11228            this.request_autoscroll(Autoscroll::fit(), cx);
11229        });
11230    }
11231
11232    pub fn duplicate_line_up(
11233        &mut self,
11234        _: &DuplicateLineUp,
11235        window: &mut Window,
11236        cx: &mut Context<Self>,
11237    ) {
11238        self.duplicate(true, true, window, cx);
11239    }
11240
11241    pub fn duplicate_line_down(
11242        &mut self,
11243        _: &DuplicateLineDown,
11244        window: &mut Window,
11245        cx: &mut Context<Self>,
11246    ) {
11247        self.duplicate(false, true, window, cx);
11248    }
11249
11250    pub fn duplicate_selection(
11251        &mut self,
11252        _: &DuplicateSelection,
11253        window: &mut Window,
11254        cx: &mut Context<Self>,
11255    ) {
11256        self.duplicate(false, false, window, cx);
11257    }
11258
11259    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11260        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11261        if self.mode.is_single_line() {
11262            cx.propagate();
11263            return;
11264        }
11265
11266        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11267        let buffer = self.buffer.read(cx).snapshot(cx);
11268
11269        let mut edits = Vec::new();
11270        let mut unfold_ranges = Vec::new();
11271        let mut refold_creases = Vec::new();
11272
11273        let selections = self.selections.all::<Point>(cx);
11274        let mut selections = selections.iter().peekable();
11275        let mut contiguous_row_selections = Vec::new();
11276        let mut new_selections = Vec::new();
11277
11278        while let Some(selection) = selections.next() {
11279            // Find all the selections that span a contiguous row range
11280            let (start_row, end_row) = consume_contiguous_rows(
11281                &mut contiguous_row_selections,
11282                selection,
11283                &display_map,
11284                &mut selections,
11285            );
11286
11287            // Move the text spanned by the row range to be before the line preceding the row range
11288            if start_row.0 > 0 {
11289                let range_to_move = Point::new(
11290                    start_row.previous_row().0,
11291                    buffer.line_len(start_row.previous_row()),
11292                )
11293                    ..Point::new(
11294                        end_row.previous_row().0,
11295                        buffer.line_len(end_row.previous_row()),
11296                    );
11297                let insertion_point = display_map
11298                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11299                    .0;
11300
11301                // Don't move lines across excerpts
11302                if buffer
11303                    .excerpt_containing(insertion_point..range_to_move.end)
11304                    .is_some()
11305                {
11306                    let text = buffer
11307                        .text_for_range(range_to_move.clone())
11308                        .flat_map(|s| s.chars())
11309                        .skip(1)
11310                        .chain(['\n'])
11311                        .collect::<String>();
11312
11313                    edits.push((
11314                        buffer.anchor_after(range_to_move.start)
11315                            ..buffer.anchor_before(range_to_move.end),
11316                        String::new(),
11317                    ));
11318                    let insertion_anchor = buffer.anchor_after(insertion_point);
11319                    edits.push((insertion_anchor..insertion_anchor, text));
11320
11321                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11322
11323                    // Move selections up
11324                    new_selections.extend(contiguous_row_selections.drain(..).map(
11325                        |mut selection| {
11326                            selection.start.row -= row_delta;
11327                            selection.end.row -= row_delta;
11328                            selection
11329                        },
11330                    ));
11331
11332                    // Move folds up
11333                    unfold_ranges.push(range_to_move.clone());
11334                    for fold in display_map.folds_in_range(
11335                        buffer.anchor_before(range_to_move.start)
11336                            ..buffer.anchor_after(range_to_move.end),
11337                    ) {
11338                        let mut start = fold.range.start.to_point(&buffer);
11339                        let mut end = fold.range.end.to_point(&buffer);
11340                        start.row -= row_delta;
11341                        end.row -= row_delta;
11342                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11343                    }
11344                }
11345            }
11346
11347            // If we didn't move line(s), preserve the existing selections
11348            new_selections.append(&mut contiguous_row_selections);
11349        }
11350
11351        self.transact(window, cx, |this, window, cx| {
11352            this.unfold_ranges(&unfold_ranges, true, true, cx);
11353            this.buffer.update(cx, |buffer, cx| {
11354                for (range, text) in edits {
11355                    buffer.edit([(range, text)], None, cx);
11356                }
11357            });
11358            this.fold_creases(refold_creases, true, window, cx);
11359            this.change_selections(Default::default(), window, cx, |s| {
11360                s.select(new_selections);
11361            })
11362        });
11363    }
11364
11365    pub fn move_line_down(
11366        &mut self,
11367        _: &MoveLineDown,
11368        window: &mut Window,
11369        cx: &mut Context<Self>,
11370    ) {
11371        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11372        if self.mode.is_single_line() {
11373            cx.propagate();
11374            return;
11375        }
11376
11377        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11378        let buffer = self.buffer.read(cx).snapshot(cx);
11379
11380        let mut edits = Vec::new();
11381        let mut unfold_ranges = Vec::new();
11382        let mut refold_creases = Vec::new();
11383
11384        let selections = self.selections.all::<Point>(cx);
11385        let mut selections = selections.iter().peekable();
11386        let mut contiguous_row_selections = Vec::new();
11387        let mut new_selections = Vec::new();
11388
11389        while let Some(selection) = selections.next() {
11390            // Find all the selections that span a contiguous row range
11391            let (start_row, end_row) = consume_contiguous_rows(
11392                &mut contiguous_row_selections,
11393                selection,
11394                &display_map,
11395                &mut selections,
11396            );
11397
11398            // Move the text spanned by the row range to be after the last line of the row range
11399            if end_row.0 <= buffer.max_point().row {
11400                let range_to_move =
11401                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11402                let insertion_point = display_map
11403                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11404                    .0;
11405
11406                // Don't move lines across excerpt boundaries
11407                if buffer
11408                    .excerpt_containing(range_to_move.start..insertion_point)
11409                    .is_some()
11410                {
11411                    let mut text = String::from("\n");
11412                    text.extend(buffer.text_for_range(range_to_move.clone()));
11413                    text.pop(); // Drop trailing newline
11414                    edits.push((
11415                        buffer.anchor_after(range_to_move.start)
11416                            ..buffer.anchor_before(range_to_move.end),
11417                        String::new(),
11418                    ));
11419                    let insertion_anchor = buffer.anchor_after(insertion_point);
11420                    edits.push((insertion_anchor..insertion_anchor, text));
11421
11422                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11423
11424                    // Move selections down
11425                    new_selections.extend(contiguous_row_selections.drain(..).map(
11426                        |mut selection| {
11427                            selection.start.row += row_delta;
11428                            selection.end.row += row_delta;
11429                            selection
11430                        },
11431                    ));
11432
11433                    // Move folds down
11434                    unfold_ranges.push(range_to_move.clone());
11435                    for fold in display_map.folds_in_range(
11436                        buffer.anchor_before(range_to_move.start)
11437                            ..buffer.anchor_after(range_to_move.end),
11438                    ) {
11439                        let mut start = fold.range.start.to_point(&buffer);
11440                        let mut end = fold.range.end.to_point(&buffer);
11441                        start.row += row_delta;
11442                        end.row += row_delta;
11443                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11444                    }
11445                }
11446            }
11447
11448            // If we didn't move line(s), preserve the existing selections
11449            new_selections.append(&mut contiguous_row_selections);
11450        }
11451
11452        self.transact(window, cx, |this, window, cx| {
11453            this.unfold_ranges(&unfold_ranges, true, true, cx);
11454            this.buffer.update(cx, |buffer, cx| {
11455                for (range, text) in edits {
11456                    buffer.edit([(range, text)], None, cx);
11457                }
11458            });
11459            this.fold_creases(refold_creases, true, window, cx);
11460            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11461        });
11462    }
11463
11464    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11465        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11466        let text_layout_details = &self.text_layout_details(window);
11467        self.transact(window, cx, |this, window, cx| {
11468            let edits = this.change_selections(Default::default(), window, cx, |s| {
11469                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11470                s.move_with(|display_map, selection| {
11471                    if !selection.is_empty() {
11472                        return;
11473                    }
11474
11475                    let mut head = selection.head();
11476                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11477                    if head.column() == display_map.line_len(head.row()) {
11478                        transpose_offset = display_map
11479                            .buffer_snapshot
11480                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11481                    }
11482
11483                    if transpose_offset == 0 {
11484                        return;
11485                    }
11486
11487                    *head.column_mut() += 1;
11488                    head = display_map.clip_point(head, Bias::Right);
11489                    let goal = SelectionGoal::HorizontalPosition(
11490                        display_map
11491                            .x_for_display_point(head, text_layout_details)
11492                            .into(),
11493                    );
11494                    selection.collapse_to(head, goal);
11495
11496                    let transpose_start = display_map
11497                        .buffer_snapshot
11498                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11499                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11500                        let transpose_end = display_map
11501                            .buffer_snapshot
11502                            .clip_offset(transpose_offset + 1, Bias::Right);
11503                        if let Some(ch) =
11504                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11505                        {
11506                            edits.push((transpose_start..transpose_offset, String::new()));
11507                            edits.push((transpose_end..transpose_end, ch.to_string()));
11508                        }
11509                    }
11510                });
11511                edits
11512            });
11513            this.buffer
11514                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11515            let selections = this.selections.all::<usize>(cx);
11516            this.change_selections(Default::default(), window, cx, |s| {
11517                s.select(selections);
11518            });
11519        });
11520    }
11521
11522    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11523        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11524        if self.mode.is_single_line() {
11525            cx.propagate();
11526            return;
11527        }
11528
11529        self.rewrap_impl(RewrapOptions::default(), cx)
11530    }
11531
11532    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11533        let buffer = self.buffer.read(cx).snapshot(cx);
11534        let selections = self.selections.all::<Point>(cx);
11535
11536        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11537        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11538            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11539                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11540                .peekable();
11541
11542            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11543                row
11544            } else {
11545                return Vec::new();
11546            };
11547
11548            let language_settings = buffer.language_settings_at(selection.head(), cx);
11549            let language_scope = buffer.language_scope_at(selection.head());
11550
11551            let indent_and_prefix_for_row =
11552                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11553                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11554                    let (comment_prefix, rewrap_prefix) =
11555                        if let Some(language_scope) = &language_scope {
11556                            let indent_end = Point::new(row, indent.len);
11557                            let comment_prefix = language_scope
11558                                .line_comment_prefixes()
11559                                .iter()
11560                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11561                                .map(|prefix| prefix.to_string());
11562                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11563                            let line_text_after_indent = buffer
11564                                .text_for_range(indent_end..line_end)
11565                                .collect::<String>();
11566                            let rewrap_prefix = language_scope
11567                                .rewrap_prefixes()
11568                                .iter()
11569                                .find_map(|prefix_regex| {
11570                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11571                                        if mat.start() == 0 {
11572                                            Some(mat.as_str().to_string())
11573                                        } else {
11574                                            None
11575                                        }
11576                                    })
11577                                })
11578                                .flatten();
11579                            (comment_prefix, rewrap_prefix)
11580                        } else {
11581                            (None, None)
11582                        };
11583                    (indent, comment_prefix, rewrap_prefix)
11584                };
11585
11586            let mut ranges = Vec::new();
11587            let from_empty_selection = selection.is_empty();
11588
11589            let mut current_range_start = first_row;
11590            let mut prev_row = first_row;
11591            let (
11592                mut current_range_indent,
11593                mut current_range_comment_prefix,
11594                mut current_range_rewrap_prefix,
11595            ) = indent_and_prefix_for_row(first_row);
11596
11597            for row in non_blank_rows_iter.skip(1) {
11598                let has_paragraph_break = row > prev_row + 1;
11599
11600                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11601                    indent_and_prefix_for_row(row);
11602
11603                let has_indent_change = row_indent != current_range_indent;
11604                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11605
11606                let has_boundary_change = has_comment_change
11607                    || row_rewrap_prefix.is_some()
11608                    || (has_indent_change && current_range_comment_prefix.is_some());
11609
11610                if has_paragraph_break || has_boundary_change {
11611                    ranges.push((
11612                        language_settings.clone(),
11613                        Point::new(current_range_start, 0)
11614                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11615                        current_range_indent,
11616                        current_range_comment_prefix.clone(),
11617                        current_range_rewrap_prefix.clone(),
11618                        from_empty_selection,
11619                    ));
11620                    current_range_start = row;
11621                    current_range_indent = row_indent;
11622                    current_range_comment_prefix = row_comment_prefix;
11623                    current_range_rewrap_prefix = row_rewrap_prefix;
11624                }
11625                prev_row = row;
11626            }
11627
11628            ranges.push((
11629                language_settings.clone(),
11630                Point::new(current_range_start, 0)
11631                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11632                current_range_indent,
11633                current_range_comment_prefix,
11634                current_range_rewrap_prefix,
11635                from_empty_selection,
11636            ));
11637
11638            ranges
11639        });
11640
11641        let mut edits = Vec::new();
11642        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11643
11644        for (
11645            language_settings,
11646            wrap_range,
11647            indent_size,
11648            comment_prefix,
11649            rewrap_prefix,
11650            from_empty_selection,
11651        ) in wrap_ranges
11652        {
11653            let mut start_row = wrap_range.start.row;
11654            let mut end_row = wrap_range.end.row;
11655
11656            // Skip selections that overlap with a range that has already been rewrapped.
11657            let selection_range = start_row..end_row;
11658            if rewrapped_row_ranges
11659                .iter()
11660                .any(|range| range.overlaps(&selection_range))
11661            {
11662                continue;
11663            }
11664
11665            let tab_size = language_settings.tab_size;
11666
11667            let indent_prefix = indent_size.chars().collect::<String>();
11668            let mut line_prefix = indent_prefix.clone();
11669            let mut inside_comment = false;
11670            if let Some(prefix) = &comment_prefix {
11671                line_prefix.push_str(prefix);
11672                inside_comment = true;
11673            }
11674            if let Some(prefix) = &rewrap_prefix {
11675                line_prefix.push_str(prefix);
11676            }
11677
11678            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11679                RewrapBehavior::InComments => inside_comment,
11680                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11681                RewrapBehavior::Anywhere => true,
11682            };
11683
11684            let should_rewrap = options.override_language_settings
11685                || allow_rewrap_based_on_language
11686                || self.hard_wrap.is_some();
11687            if !should_rewrap {
11688                continue;
11689            }
11690
11691            if from_empty_selection {
11692                'expand_upwards: while start_row > 0 {
11693                    let prev_row = start_row - 1;
11694                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11695                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11696                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11697                    {
11698                        start_row = prev_row;
11699                    } else {
11700                        break 'expand_upwards;
11701                    }
11702                }
11703
11704                'expand_downwards: while end_row < buffer.max_point().row {
11705                    let next_row = end_row + 1;
11706                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11707                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11708                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11709                    {
11710                        end_row = next_row;
11711                    } else {
11712                        break 'expand_downwards;
11713                    }
11714                }
11715            }
11716
11717            let start = Point::new(start_row, 0);
11718            let start_offset = start.to_offset(&buffer);
11719            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11720            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11721            let Some(lines_without_prefixes) = selection_text
11722                .lines()
11723                .enumerate()
11724                .map(|(ix, line)| {
11725                    let line_trimmed = line.trim_start();
11726                    if rewrap_prefix.is_some() && ix > 0 {
11727                        Ok(line_trimmed)
11728                    } else {
11729                        line_trimmed
11730                            .strip_prefix(&line_prefix.trim_start())
11731                            .with_context(|| {
11732                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11733                            })
11734                    }
11735                })
11736                .collect::<Result<Vec<_>, _>>()
11737                .log_err()
11738            else {
11739                continue;
11740            };
11741
11742            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11743                buffer
11744                    .language_settings_at(Point::new(start_row, 0), cx)
11745                    .preferred_line_length as usize
11746            });
11747
11748            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11749                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11750            } else {
11751                line_prefix.clone()
11752            };
11753
11754            let wrapped_text = wrap_with_prefix(
11755                line_prefix,
11756                subsequent_lines_prefix,
11757                lines_without_prefixes.join("\n"),
11758                wrap_column,
11759                tab_size,
11760                options.preserve_existing_whitespace,
11761            );
11762
11763            // TODO: should always use char-based diff while still supporting cursor behavior that
11764            // matches vim.
11765            let mut diff_options = DiffOptions::default();
11766            if options.override_language_settings {
11767                diff_options.max_word_diff_len = 0;
11768                diff_options.max_word_diff_line_count = 0;
11769            } else {
11770                diff_options.max_word_diff_len = usize::MAX;
11771                diff_options.max_word_diff_line_count = usize::MAX;
11772            }
11773
11774            for (old_range, new_text) in
11775                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11776            {
11777                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11778                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11779                edits.push((edit_start..edit_end, new_text));
11780            }
11781
11782            rewrapped_row_ranges.push(start_row..=end_row);
11783        }
11784
11785        self.buffer
11786            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11787    }
11788
11789    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11790        let mut text = String::new();
11791        let buffer = self.buffer.read(cx).snapshot(cx);
11792        let mut selections = self.selections.all::<Point>(cx);
11793        let mut clipboard_selections = Vec::with_capacity(selections.len());
11794        {
11795            let max_point = buffer.max_point();
11796            let mut is_first = true;
11797            for selection in &mut selections {
11798                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11799                if is_entire_line {
11800                    selection.start = Point::new(selection.start.row, 0);
11801                    if !selection.is_empty() && selection.end.column == 0 {
11802                        selection.end = cmp::min(max_point, selection.end);
11803                    } else {
11804                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11805                    }
11806                    selection.goal = SelectionGoal::None;
11807                }
11808                if is_first {
11809                    is_first = false;
11810                } else {
11811                    text += "\n";
11812                }
11813                let mut len = 0;
11814                for chunk in buffer.text_for_range(selection.start..selection.end) {
11815                    text.push_str(chunk);
11816                    len += chunk.len();
11817                }
11818                clipboard_selections.push(ClipboardSelection {
11819                    len,
11820                    is_entire_line,
11821                    first_line_indent: buffer
11822                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11823                        .len,
11824                });
11825            }
11826        }
11827
11828        self.transact(window, cx, |this, window, cx| {
11829            this.change_selections(Default::default(), window, cx, |s| {
11830                s.select(selections);
11831            });
11832            this.insert("", window, cx);
11833        });
11834        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11835    }
11836
11837    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11838        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11839        let item = self.cut_common(window, cx);
11840        cx.write_to_clipboard(item);
11841    }
11842
11843    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11845        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11846            s.move_with(|snapshot, sel| {
11847                if sel.is_empty() {
11848                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11849                }
11850            });
11851        });
11852        let item = self.cut_common(window, cx);
11853        cx.set_global(KillRing(item))
11854    }
11855
11856    pub fn kill_ring_yank(
11857        &mut self,
11858        _: &KillRingYank,
11859        window: &mut Window,
11860        cx: &mut Context<Self>,
11861    ) {
11862        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11863        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11864            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11865                (kill_ring.text().to_string(), kill_ring.metadata_json())
11866            } else {
11867                return;
11868            }
11869        } else {
11870            return;
11871        };
11872        self.do_paste(&text, metadata, false, window, cx);
11873    }
11874
11875    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11876        self.do_copy(true, cx);
11877    }
11878
11879    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11880        self.do_copy(false, cx);
11881    }
11882
11883    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11884        let selections = self.selections.all::<Point>(cx);
11885        let buffer = self.buffer.read(cx).read(cx);
11886        let mut text = String::new();
11887
11888        let mut clipboard_selections = Vec::with_capacity(selections.len());
11889        {
11890            let max_point = buffer.max_point();
11891            let mut is_first = true;
11892            for selection in &selections {
11893                let mut start = selection.start;
11894                let mut end = selection.end;
11895                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11896                if is_entire_line {
11897                    start = Point::new(start.row, 0);
11898                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11899                }
11900
11901                let mut trimmed_selections = Vec::new();
11902                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11903                    let row = MultiBufferRow(start.row);
11904                    let first_indent = buffer.indent_size_for_line(row);
11905                    if first_indent.len == 0 || start.column > first_indent.len {
11906                        trimmed_selections.push(start..end);
11907                    } else {
11908                        trimmed_selections.push(
11909                            Point::new(row.0, first_indent.len)
11910                                ..Point::new(row.0, buffer.line_len(row)),
11911                        );
11912                        for row in start.row + 1..=end.row {
11913                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11914                            if row == end.row {
11915                                line_len = end.column;
11916                            }
11917                            if line_len == 0 {
11918                                trimmed_selections
11919                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11920                                continue;
11921                            }
11922                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11923                            if row_indent_size.len >= first_indent.len {
11924                                trimmed_selections.push(
11925                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11926                                );
11927                            } else {
11928                                trimmed_selections.clear();
11929                                trimmed_selections.push(start..end);
11930                                break;
11931                            }
11932                        }
11933                    }
11934                } else {
11935                    trimmed_selections.push(start..end);
11936                }
11937
11938                for trimmed_range in trimmed_selections {
11939                    if is_first {
11940                        is_first = false;
11941                    } else {
11942                        text += "\n";
11943                    }
11944                    let mut len = 0;
11945                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11946                        text.push_str(chunk);
11947                        len += chunk.len();
11948                    }
11949                    clipboard_selections.push(ClipboardSelection {
11950                        len,
11951                        is_entire_line,
11952                        first_line_indent: buffer
11953                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11954                            .len,
11955                    });
11956                }
11957            }
11958        }
11959
11960        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11961            text,
11962            clipboard_selections,
11963        ));
11964    }
11965
11966    pub fn do_paste(
11967        &mut self,
11968        text: &String,
11969        clipboard_selections: Option<Vec<ClipboardSelection>>,
11970        handle_entire_lines: bool,
11971        window: &mut Window,
11972        cx: &mut Context<Self>,
11973    ) {
11974        if self.read_only(cx) {
11975            return;
11976        }
11977
11978        let clipboard_text = Cow::Borrowed(text);
11979
11980        self.transact(window, cx, |this, window, cx| {
11981            if let Some(mut clipboard_selections) = clipboard_selections {
11982                let old_selections = this.selections.all::<usize>(cx);
11983                let all_selections_were_entire_line =
11984                    clipboard_selections.iter().all(|s| s.is_entire_line);
11985                let first_selection_indent_column =
11986                    clipboard_selections.first().map(|s| s.first_line_indent);
11987                if clipboard_selections.len() != old_selections.len() {
11988                    clipboard_selections.drain(..);
11989                }
11990                let cursor_offset = this.selections.last::<usize>(cx).head();
11991                let mut auto_indent_on_paste = true;
11992
11993                this.buffer.update(cx, |buffer, cx| {
11994                    let snapshot = buffer.read(cx);
11995                    auto_indent_on_paste = snapshot
11996                        .language_settings_at(cursor_offset, cx)
11997                        .auto_indent_on_paste;
11998
11999                    let mut start_offset = 0;
12000                    let mut edits = Vec::new();
12001                    let mut original_indent_columns = Vec::new();
12002                    for (ix, selection) in old_selections.iter().enumerate() {
12003                        let to_insert;
12004                        let entire_line;
12005                        let original_indent_column;
12006                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12007                            let end_offset = start_offset + clipboard_selection.len;
12008                            to_insert = &clipboard_text[start_offset..end_offset];
12009                            entire_line = clipboard_selection.is_entire_line;
12010                            start_offset = end_offset + 1;
12011                            original_indent_column = Some(clipboard_selection.first_line_indent);
12012                        } else {
12013                            to_insert = clipboard_text.as_str();
12014                            entire_line = all_selections_were_entire_line;
12015                            original_indent_column = first_selection_indent_column
12016                        }
12017
12018                        // If the corresponding selection was empty when this slice of the
12019                        // clipboard text was written, then the entire line containing the
12020                        // selection was copied. If this selection is also currently empty,
12021                        // then paste the line before the current line of the buffer.
12022                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12023                            let column = selection.start.to_point(&snapshot).column as usize;
12024                            let line_start = selection.start - column;
12025                            line_start..line_start
12026                        } else {
12027                            selection.range()
12028                        };
12029
12030                        edits.push((range, to_insert));
12031                        original_indent_columns.push(original_indent_column);
12032                    }
12033                    drop(snapshot);
12034
12035                    buffer.edit(
12036                        edits,
12037                        if auto_indent_on_paste {
12038                            Some(AutoindentMode::Block {
12039                                original_indent_columns,
12040                            })
12041                        } else {
12042                            None
12043                        },
12044                        cx,
12045                    );
12046                });
12047
12048                let selections = this.selections.all::<usize>(cx);
12049                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12050            } else {
12051                this.insert(&clipboard_text, window, cx);
12052            }
12053        });
12054    }
12055
12056    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12057        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12058        if let Some(item) = cx.read_from_clipboard() {
12059            let entries = item.entries();
12060
12061            match entries.first() {
12062                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12063                // of all the pasted entries.
12064                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12065                    .do_paste(
12066                        clipboard_string.text(),
12067                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12068                        true,
12069                        window,
12070                        cx,
12071                    ),
12072                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12073            }
12074        }
12075    }
12076
12077    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12078        if self.read_only(cx) {
12079            return;
12080        }
12081
12082        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12083
12084        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12085            if let Some((selections, _)) =
12086                self.selection_history.transaction(transaction_id).cloned()
12087            {
12088                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12089                    s.select_anchors(selections.to_vec());
12090                });
12091            } else {
12092                log::error!(
12093                    "No entry in selection_history found for undo. \
12094                     This may correspond to a bug where undo does not update the selection. \
12095                     If this is occurring, please add details to \
12096                     https://github.com/zed-industries/zed/issues/22692"
12097                );
12098            }
12099            self.request_autoscroll(Autoscroll::fit(), cx);
12100            self.unmark_text(window, cx);
12101            self.refresh_inline_completion(true, false, window, cx);
12102            cx.emit(EditorEvent::Edited { transaction_id });
12103            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12104        }
12105    }
12106
12107    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12108        if self.read_only(cx) {
12109            return;
12110        }
12111
12112        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12113
12114        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12115            if let Some((_, Some(selections))) =
12116                self.selection_history.transaction(transaction_id).cloned()
12117            {
12118                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12119                    s.select_anchors(selections.to_vec());
12120                });
12121            } else {
12122                log::error!(
12123                    "No entry in selection_history found for redo. \
12124                     This may correspond to a bug where undo does not update the selection. \
12125                     If this is occurring, please add details to \
12126                     https://github.com/zed-industries/zed/issues/22692"
12127                );
12128            }
12129            self.request_autoscroll(Autoscroll::fit(), cx);
12130            self.unmark_text(window, cx);
12131            self.refresh_inline_completion(true, false, window, cx);
12132            cx.emit(EditorEvent::Edited { transaction_id });
12133        }
12134    }
12135
12136    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12137        self.buffer
12138            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12139    }
12140
12141    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12142        self.buffer
12143            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12144    }
12145
12146    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12148        self.change_selections(Default::default(), window, cx, |s| {
12149            s.move_with(|map, selection| {
12150                let cursor = if selection.is_empty() {
12151                    movement::left(map, selection.start)
12152                } else {
12153                    selection.start
12154                };
12155                selection.collapse_to(cursor, SelectionGoal::None);
12156            });
12157        })
12158    }
12159
12160    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12161        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12162        self.change_selections(Default::default(), window, cx, |s| {
12163            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12164        })
12165    }
12166
12167    pub fn move_right(&mut self, _: &MoveRight, 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::right(map, selection.end)
12173                } else {
12174                    selection.end
12175                };
12176                selection.collapse_to(cursor, SelectionGoal::None)
12177            });
12178        })
12179    }
12180
12181    pub fn select_right(&mut self, _: &SelectRight, 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::right(map, head), SelectionGoal::None));
12185        })
12186    }
12187
12188    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12189        if self.take_rename(true, window, cx).is_some() {
12190            return;
12191        }
12192
12193        if self.mode.is_single_line() {
12194            cx.propagate();
12195            return;
12196        }
12197
12198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12199
12200        let text_layout_details = &self.text_layout_details(window);
12201        let selection_count = self.selections.count();
12202        let first_selection = self.selections.first_anchor();
12203
12204        self.change_selections(Default::default(), window, cx, |s| {
12205            s.move_with(|map, selection| {
12206                if !selection.is_empty() {
12207                    selection.goal = SelectionGoal::None;
12208                }
12209                let (cursor, goal) = movement::up(
12210                    map,
12211                    selection.start,
12212                    selection.goal,
12213                    false,
12214                    text_layout_details,
12215                );
12216                selection.collapse_to(cursor, goal);
12217            });
12218        });
12219
12220        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12221        {
12222            cx.propagate();
12223        }
12224    }
12225
12226    pub fn move_up_by_lines(
12227        &mut self,
12228        action: &MoveUpByLines,
12229        window: &mut Window,
12230        cx: &mut Context<Self>,
12231    ) {
12232        if self.take_rename(true, window, cx).is_some() {
12233            return;
12234        }
12235
12236        if self.mode.is_single_line() {
12237            cx.propagate();
12238            return;
12239        }
12240
12241        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12242
12243        let text_layout_details = &self.text_layout_details(window);
12244
12245        self.change_selections(Default::default(), window, cx, |s| {
12246            s.move_with(|map, selection| {
12247                if !selection.is_empty() {
12248                    selection.goal = SelectionGoal::None;
12249                }
12250                let (cursor, goal) = movement::up_by_rows(
12251                    map,
12252                    selection.start,
12253                    action.lines,
12254                    selection.goal,
12255                    false,
12256                    text_layout_details,
12257                );
12258                selection.collapse_to(cursor, goal);
12259            });
12260        })
12261    }
12262
12263    pub fn move_down_by_lines(
12264        &mut self,
12265        action: &MoveDownByLines,
12266        window: &mut Window,
12267        cx: &mut Context<Self>,
12268    ) {
12269        if self.take_rename(true, window, cx).is_some() {
12270            return;
12271        }
12272
12273        if self.mode.is_single_line() {
12274            cx.propagate();
12275            return;
12276        }
12277
12278        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12279
12280        let text_layout_details = &self.text_layout_details(window);
12281
12282        self.change_selections(Default::default(), window, cx, |s| {
12283            s.move_with(|map, selection| {
12284                if !selection.is_empty() {
12285                    selection.goal = SelectionGoal::None;
12286                }
12287                let (cursor, goal) = movement::down_by_rows(
12288                    map,
12289                    selection.start,
12290                    action.lines,
12291                    selection.goal,
12292                    false,
12293                    text_layout_details,
12294                );
12295                selection.collapse_to(cursor, goal);
12296            });
12297        })
12298    }
12299
12300    pub fn select_down_by_lines(
12301        &mut self,
12302        action: &SelectDownByLines,
12303        window: &mut Window,
12304        cx: &mut Context<Self>,
12305    ) {
12306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12307        let text_layout_details = &self.text_layout_details(window);
12308        self.change_selections(Default::default(), window, cx, |s| {
12309            s.move_heads_with(|map, head, goal| {
12310                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12311            })
12312        })
12313    }
12314
12315    pub fn select_up_by_lines(
12316        &mut self,
12317        action: &SelectUpByLines,
12318        window: &mut Window,
12319        cx: &mut Context<Self>,
12320    ) {
12321        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12322        let text_layout_details = &self.text_layout_details(window);
12323        self.change_selections(Default::default(), window, cx, |s| {
12324            s.move_heads_with(|map, head, goal| {
12325                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12326            })
12327        })
12328    }
12329
12330    pub fn select_page_up(
12331        &mut self,
12332        _: &SelectPageUp,
12333        window: &mut Window,
12334        cx: &mut Context<Self>,
12335    ) {
12336        let Some(row_count) = self.visible_row_count() else {
12337            return;
12338        };
12339
12340        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12341
12342        let text_layout_details = &self.text_layout_details(window);
12343
12344        self.change_selections(Default::default(), window, cx, |s| {
12345            s.move_heads_with(|map, head, goal| {
12346                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12347            })
12348        })
12349    }
12350
12351    pub fn move_page_up(
12352        &mut self,
12353        action: &MovePageUp,
12354        window: &mut Window,
12355        cx: &mut Context<Self>,
12356    ) {
12357        if self.take_rename(true, window, cx).is_some() {
12358            return;
12359        }
12360
12361        if self
12362            .context_menu
12363            .borrow_mut()
12364            .as_mut()
12365            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12366            .unwrap_or(false)
12367        {
12368            return;
12369        }
12370
12371        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12372            cx.propagate();
12373            return;
12374        }
12375
12376        let Some(row_count) = self.visible_row_count() else {
12377            return;
12378        };
12379
12380        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12381
12382        let effects = if action.center_cursor {
12383            SelectionEffects::scroll(Autoscroll::center())
12384        } else {
12385            SelectionEffects::default()
12386        };
12387
12388        let text_layout_details = &self.text_layout_details(window);
12389
12390        self.change_selections(effects, window, cx, |s| {
12391            s.move_with(|map, selection| {
12392                if !selection.is_empty() {
12393                    selection.goal = SelectionGoal::None;
12394                }
12395                let (cursor, goal) = movement::up_by_rows(
12396                    map,
12397                    selection.end,
12398                    row_count,
12399                    selection.goal,
12400                    false,
12401                    text_layout_details,
12402                );
12403                selection.collapse_to(cursor, goal);
12404            });
12405        });
12406    }
12407
12408    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12410        let text_layout_details = &self.text_layout_details(window);
12411        self.change_selections(Default::default(), window, cx, |s| {
12412            s.move_heads_with(|map, head, goal| {
12413                movement::up(map, head, goal, false, text_layout_details)
12414            })
12415        })
12416    }
12417
12418    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12419        self.take_rename(true, window, cx);
12420
12421        if self.mode.is_single_line() {
12422            cx.propagate();
12423            return;
12424        }
12425
12426        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12427
12428        let text_layout_details = &self.text_layout_details(window);
12429        let selection_count = self.selections.count();
12430        let first_selection = self.selections.first_anchor();
12431
12432        self.change_selections(Default::default(), window, cx, |s| {
12433            s.move_with(|map, selection| {
12434                if !selection.is_empty() {
12435                    selection.goal = SelectionGoal::None;
12436                }
12437                let (cursor, goal) = movement::down(
12438                    map,
12439                    selection.end,
12440                    selection.goal,
12441                    false,
12442                    text_layout_details,
12443                );
12444                selection.collapse_to(cursor, goal);
12445            });
12446        });
12447
12448        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12449        {
12450            cx.propagate();
12451        }
12452    }
12453
12454    pub fn select_page_down(
12455        &mut self,
12456        _: &SelectPageDown,
12457        window: &mut Window,
12458        cx: &mut Context<Self>,
12459    ) {
12460        let Some(row_count) = self.visible_row_count() else {
12461            return;
12462        };
12463
12464        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12465
12466        let text_layout_details = &self.text_layout_details(window);
12467
12468        self.change_selections(Default::default(), window, cx, |s| {
12469            s.move_heads_with(|map, head, goal| {
12470                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12471            })
12472        })
12473    }
12474
12475    pub fn move_page_down(
12476        &mut self,
12477        action: &MovePageDown,
12478        window: &mut Window,
12479        cx: &mut Context<Self>,
12480    ) {
12481        if self.take_rename(true, window, cx).is_some() {
12482            return;
12483        }
12484
12485        if self
12486            .context_menu
12487            .borrow_mut()
12488            .as_mut()
12489            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12490            .unwrap_or(false)
12491        {
12492            return;
12493        }
12494
12495        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12496            cx.propagate();
12497            return;
12498        }
12499
12500        let Some(row_count) = self.visible_row_count() else {
12501            return;
12502        };
12503
12504        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12505
12506        let effects = if action.center_cursor {
12507            SelectionEffects::scroll(Autoscroll::center())
12508        } else {
12509            SelectionEffects::default()
12510        };
12511
12512        let text_layout_details = &self.text_layout_details(window);
12513        self.change_selections(effects, window, cx, |s| {
12514            s.move_with(|map, selection| {
12515                if !selection.is_empty() {
12516                    selection.goal = SelectionGoal::None;
12517                }
12518                let (cursor, goal) = movement::down_by_rows(
12519                    map,
12520                    selection.end,
12521                    row_count,
12522                    selection.goal,
12523                    false,
12524                    text_layout_details,
12525                );
12526                selection.collapse_to(cursor, goal);
12527            });
12528        });
12529    }
12530
12531    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12532        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12533        let text_layout_details = &self.text_layout_details(window);
12534        self.change_selections(Default::default(), window, cx, |s| {
12535            s.move_heads_with(|map, head, goal| {
12536                movement::down(map, head, goal, false, text_layout_details)
12537            })
12538        });
12539    }
12540
12541    pub fn context_menu_first(
12542        &mut self,
12543        _: &ContextMenuFirst,
12544        window: &mut Window,
12545        cx: &mut Context<Self>,
12546    ) {
12547        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12548            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12549        }
12550    }
12551
12552    pub fn context_menu_prev(
12553        &mut self,
12554        _: &ContextMenuPrevious,
12555        window: &mut Window,
12556        cx: &mut Context<Self>,
12557    ) {
12558        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12559            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12560        }
12561    }
12562
12563    pub fn context_menu_next(
12564        &mut self,
12565        _: &ContextMenuNext,
12566        window: &mut Window,
12567        cx: &mut Context<Self>,
12568    ) {
12569        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12570            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12571        }
12572    }
12573
12574    pub fn context_menu_last(
12575        &mut self,
12576        _: &ContextMenuLast,
12577        window: &mut Window,
12578        cx: &mut Context<Self>,
12579    ) {
12580        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12581            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12582        }
12583    }
12584
12585    pub fn move_to_previous_word_start(
12586        &mut self,
12587        _: &MoveToPreviousWordStart,
12588        window: &mut Window,
12589        cx: &mut Context<Self>,
12590    ) {
12591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12592        self.change_selections(Default::default(), window, cx, |s| {
12593            s.move_cursors_with(|map, head, _| {
12594                (
12595                    movement::previous_word_start(map, head),
12596                    SelectionGoal::None,
12597                )
12598            });
12599        })
12600    }
12601
12602    pub fn move_to_previous_subword_start(
12603        &mut self,
12604        _: &MoveToPreviousSubwordStart,
12605        window: &mut Window,
12606        cx: &mut Context<Self>,
12607    ) {
12608        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12609        self.change_selections(Default::default(), window, cx, |s| {
12610            s.move_cursors_with(|map, head, _| {
12611                (
12612                    movement::previous_subword_start(map, head),
12613                    SelectionGoal::None,
12614                )
12615            });
12616        })
12617    }
12618
12619    pub fn select_to_previous_word_start(
12620        &mut self,
12621        _: &SelectToPreviousWordStart,
12622        window: &mut Window,
12623        cx: &mut Context<Self>,
12624    ) {
12625        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12626        self.change_selections(Default::default(), window, cx, |s| {
12627            s.move_heads_with(|map, head, _| {
12628                (
12629                    movement::previous_word_start(map, head),
12630                    SelectionGoal::None,
12631                )
12632            });
12633        })
12634    }
12635
12636    pub fn select_to_previous_subword_start(
12637        &mut self,
12638        _: &SelectToPreviousSubwordStart,
12639        window: &mut Window,
12640        cx: &mut Context<Self>,
12641    ) {
12642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12643        self.change_selections(Default::default(), window, cx, |s| {
12644            s.move_heads_with(|map, head, _| {
12645                (
12646                    movement::previous_subword_start(map, head),
12647                    SelectionGoal::None,
12648                )
12649            });
12650        })
12651    }
12652
12653    pub fn delete_to_previous_word_start(
12654        &mut self,
12655        action: &DeleteToPreviousWordStart,
12656        window: &mut Window,
12657        cx: &mut Context<Self>,
12658    ) {
12659        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12660        self.transact(window, cx, |this, window, cx| {
12661            this.select_autoclose_pair(window, cx);
12662            this.change_selections(Default::default(), window, cx, |s| {
12663                s.move_with(|map, selection| {
12664                    if selection.is_empty() {
12665                        let cursor = if action.ignore_newlines {
12666                            movement::previous_word_start(map, selection.head())
12667                        } else {
12668                            movement::previous_word_start_or_newline(map, selection.head())
12669                        };
12670                        selection.set_head(cursor, SelectionGoal::None);
12671                    }
12672                });
12673            });
12674            this.insert("", window, cx);
12675        });
12676    }
12677
12678    pub fn delete_to_previous_subword_start(
12679        &mut self,
12680        _: &DeleteToPreviousSubwordStart,
12681        window: &mut Window,
12682        cx: &mut Context<Self>,
12683    ) {
12684        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12685        self.transact(window, cx, |this, window, cx| {
12686            this.select_autoclose_pair(window, cx);
12687            this.change_selections(Default::default(), window, cx, |s| {
12688                s.move_with(|map, selection| {
12689                    if selection.is_empty() {
12690                        let cursor = movement::previous_subword_start(map, selection.head());
12691                        selection.set_head(cursor, SelectionGoal::None);
12692                    }
12693                });
12694            });
12695            this.insert("", window, cx);
12696        });
12697    }
12698
12699    pub fn move_to_next_word_end(
12700        &mut self,
12701        _: &MoveToNextWordEnd,
12702        window: &mut Window,
12703        cx: &mut Context<Self>,
12704    ) {
12705        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12706        self.change_selections(Default::default(), window, cx, |s| {
12707            s.move_cursors_with(|map, head, _| {
12708                (movement::next_word_end(map, head), SelectionGoal::None)
12709            });
12710        })
12711    }
12712
12713    pub fn move_to_next_subword_end(
12714        &mut self,
12715        _: &MoveToNextSubwordEnd,
12716        window: &mut Window,
12717        cx: &mut Context<Self>,
12718    ) {
12719        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12720        self.change_selections(Default::default(), window, cx, |s| {
12721            s.move_cursors_with(|map, head, _| {
12722                (movement::next_subword_end(map, head), SelectionGoal::None)
12723            });
12724        })
12725    }
12726
12727    pub fn select_to_next_word_end(
12728        &mut self,
12729        _: &SelectToNextWordEnd,
12730        window: &mut Window,
12731        cx: &mut Context<Self>,
12732    ) {
12733        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12734        self.change_selections(Default::default(), window, cx, |s| {
12735            s.move_heads_with(|map, head, _| {
12736                (movement::next_word_end(map, head), SelectionGoal::None)
12737            });
12738        })
12739    }
12740
12741    pub fn select_to_next_subword_end(
12742        &mut self,
12743        _: &SelectToNextSubwordEnd,
12744        window: &mut Window,
12745        cx: &mut Context<Self>,
12746    ) {
12747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12748        self.change_selections(Default::default(), window, cx, |s| {
12749            s.move_heads_with(|map, head, _| {
12750                (movement::next_subword_end(map, head), SelectionGoal::None)
12751            });
12752        })
12753    }
12754
12755    pub fn delete_to_next_word_end(
12756        &mut self,
12757        action: &DeleteToNextWordEnd,
12758        window: &mut Window,
12759        cx: &mut Context<Self>,
12760    ) {
12761        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12762        self.transact(window, cx, |this, window, cx| {
12763            this.change_selections(Default::default(), window, cx, |s| {
12764                s.move_with(|map, selection| {
12765                    if selection.is_empty() {
12766                        let cursor = if action.ignore_newlines {
12767                            movement::next_word_end(map, selection.head())
12768                        } else {
12769                            movement::next_word_end_or_newline(map, selection.head())
12770                        };
12771                        selection.set_head(cursor, SelectionGoal::None);
12772                    }
12773                });
12774            });
12775            this.insert("", window, cx);
12776        });
12777    }
12778
12779    pub fn delete_to_next_subword_end(
12780        &mut self,
12781        _: &DeleteToNextSubwordEnd,
12782        window: &mut Window,
12783        cx: &mut Context<Self>,
12784    ) {
12785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12786        self.transact(window, cx, |this, window, cx| {
12787            this.change_selections(Default::default(), window, cx, |s| {
12788                s.move_with(|map, selection| {
12789                    if selection.is_empty() {
12790                        let cursor = movement::next_subword_end(map, selection.head());
12791                        selection.set_head(cursor, SelectionGoal::None);
12792                    }
12793                });
12794            });
12795            this.insert("", window, cx);
12796        });
12797    }
12798
12799    pub fn move_to_beginning_of_line(
12800        &mut self,
12801        action: &MoveToBeginningOfLine,
12802        window: &mut Window,
12803        cx: &mut Context<Self>,
12804    ) {
12805        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12806        self.change_selections(Default::default(), window, cx, |s| {
12807            s.move_cursors_with(|map, head, _| {
12808                (
12809                    movement::indented_line_beginning(
12810                        map,
12811                        head,
12812                        action.stop_at_soft_wraps,
12813                        action.stop_at_indent,
12814                    ),
12815                    SelectionGoal::None,
12816                )
12817            });
12818        })
12819    }
12820
12821    pub fn select_to_beginning_of_line(
12822        &mut self,
12823        action: &SelectToBeginningOfLine,
12824        window: &mut Window,
12825        cx: &mut Context<Self>,
12826    ) {
12827        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12828        self.change_selections(Default::default(), window, cx, |s| {
12829            s.move_heads_with(|map, head, _| {
12830                (
12831                    movement::indented_line_beginning(
12832                        map,
12833                        head,
12834                        action.stop_at_soft_wraps,
12835                        action.stop_at_indent,
12836                    ),
12837                    SelectionGoal::None,
12838                )
12839            });
12840        });
12841    }
12842
12843    pub fn delete_to_beginning_of_line(
12844        &mut self,
12845        action: &DeleteToBeginningOfLine,
12846        window: &mut Window,
12847        cx: &mut Context<Self>,
12848    ) {
12849        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12850        self.transact(window, cx, |this, window, cx| {
12851            this.change_selections(Default::default(), window, cx, |s| {
12852                s.move_with(|_, selection| {
12853                    selection.reversed = true;
12854                });
12855            });
12856
12857            this.select_to_beginning_of_line(
12858                &SelectToBeginningOfLine {
12859                    stop_at_soft_wraps: false,
12860                    stop_at_indent: action.stop_at_indent,
12861                },
12862                window,
12863                cx,
12864            );
12865            this.backspace(&Backspace, window, cx);
12866        });
12867    }
12868
12869    pub fn move_to_end_of_line(
12870        &mut self,
12871        action: &MoveToEndOfLine,
12872        window: &mut Window,
12873        cx: &mut Context<Self>,
12874    ) {
12875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12876        self.change_selections(Default::default(), window, cx, |s| {
12877            s.move_cursors_with(|map, head, _| {
12878                (
12879                    movement::line_end(map, head, action.stop_at_soft_wraps),
12880                    SelectionGoal::None,
12881                )
12882            });
12883        })
12884    }
12885
12886    pub fn select_to_end_of_line(
12887        &mut self,
12888        action: &SelectToEndOfLine,
12889        window: &mut Window,
12890        cx: &mut Context<Self>,
12891    ) {
12892        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12893        self.change_selections(Default::default(), window, cx, |s| {
12894            s.move_heads_with(|map, head, _| {
12895                (
12896                    movement::line_end(map, head, action.stop_at_soft_wraps),
12897                    SelectionGoal::None,
12898                )
12899            });
12900        })
12901    }
12902
12903    pub fn delete_to_end_of_line(
12904        &mut self,
12905        _: &DeleteToEndOfLine,
12906        window: &mut Window,
12907        cx: &mut Context<Self>,
12908    ) {
12909        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12910        self.transact(window, cx, |this, window, cx| {
12911            this.select_to_end_of_line(
12912                &SelectToEndOfLine {
12913                    stop_at_soft_wraps: false,
12914                },
12915                window,
12916                cx,
12917            );
12918            this.delete(&Delete, window, cx);
12919        });
12920    }
12921
12922    pub fn cut_to_end_of_line(
12923        &mut self,
12924        _: &CutToEndOfLine,
12925        window: &mut Window,
12926        cx: &mut Context<Self>,
12927    ) {
12928        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12929        self.transact(window, cx, |this, window, cx| {
12930            this.select_to_end_of_line(
12931                &SelectToEndOfLine {
12932                    stop_at_soft_wraps: false,
12933                },
12934                window,
12935                cx,
12936            );
12937            this.cut(&Cut, window, cx);
12938        });
12939    }
12940
12941    pub fn move_to_start_of_paragraph(
12942        &mut self,
12943        _: &MoveToStartOfParagraph,
12944        window: &mut Window,
12945        cx: &mut Context<Self>,
12946    ) {
12947        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12948            cx.propagate();
12949            return;
12950        }
12951        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12952        self.change_selections(Default::default(), window, cx, |s| {
12953            s.move_with(|map, selection| {
12954                selection.collapse_to(
12955                    movement::start_of_paragraph(map, selection.head(), 1),
12956                    SelectionGoal::None,
12957                )
12958            });
12959        })
12960    }
12961
12962    pub fn move_to_end_of_paragraph(
12963        &mut self,
12964        _: &MoveToEndOfParagraph,
12965        window: &mut Window,
12966        cx: &mut Context<Self>,
12967    ) {
12968        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12969            cx.propagate();
12970            return;
12971        }
12972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12973        self.change_selections(Default::default(), window, cx, |s| {
12974            s.move_with(|map, selection| {
12975                selection.collapse_to(
12976                    movement::end_of_paragraph(map, selection.head(), 1),
12977                    SelectionGoal::None,
12978                )
12979            });
12980        })
12981    }
12982
12983    pub fn select_to_start_of_paragraph(
12984        &mut self,
12985        _: &SelectToStartOfParagraph,
12986        window: &mut Window,
12987        cx: &mut Context<Self>,
12988    ) {
12989        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12990            cx.propagate();
12991            return;
12992        }
12993        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12994        self.change_selections(Default::default(), window, cx, |s| {
12995            s.move_heads_with(|map, head, _| {
12996                (
12997                    movement::start_of_paragraph(map, head, 1),
12998                    SelectionGoal::None,
12999                )
13000            });
13001        })
13002    }
13003
13004    pub fn select_to_end_of_paragraph(
13005        &mut self,
13006        _: &SelectToEndOfParagraph,
13007        window: &mut Window,
13008        cx: &mut Context<Self>,
13009    ) {
13010        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13011            cx.propagate();
13012            return;
13013        }
13014        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13015        self.change_selections(Default::default(), window, cx, |s| {
13016            s.move_heads_with(|map, head, _| {
13017                (
13018                    movement::end_of_paragraph(map, head, 1),
13019                    SelectionGoal::None,
13020                )
13021            });
13022        })
13023    }
13024
13025    pub fn move_to_start_of_excerpt(
13026        &mut self,
13027        _: &MoveToStartOfExcerpt,
13028        window: &mut Window,
13029        cx: &mut Context<Self>,
13030    ) {
13031        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13032            cx.propagate();
13033            return;
13034        }
13035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13036        self.change_selections(Default::default(), window, cx, |s| {
13037            s.move_with(|map, selection| {
13038                selection.collapse_to(
13039                    movement::start_of_excerpt(
13040                        map,
13041                        selection.head(),
13042                        workspace::searchable::Direction::Prev,
13043                    ),
13044                    SelectionGoal::None,
13045                )
13046            });
13047        })
13048    }
13049
13050    pub fn move_to_start_of_next_excerpt(
13051        &mut self,
13052        _: &MoveToStartOfNextExcerpt,
13053        window: &mut Window,
13054        cx: &mut Context<Self>,
13055    ) {
13056        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13057            cx.propagate();
13058            return;
13059        }
13060
13061        self.change_selections(Default::default(), window, cx, |s| {
13062            s.move_with(|map, selection| {
13063                selection.collapse_to(
13064                    movement::start_of_excerpt(
13065                        map,
13066                        selection.head(),
13067                        workspace::searchable::Direction::Next,
13068                    ),
13069                    SelectionGoal::None,
13070                )
13071            });
13072        })
13073    }
13074
13075    pub fn move_to_end_of_excerpt(
13076        &mut self,
13077        _: &MoveToEndOfExcerpt,
13078        window: &mut Window,
13079        cx: &mut Context<Self>,
13080    ) {
13081        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13082            cx.propagate();
13083            return;
13084        }
13085        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13086        self.change_selections(Default::default(), window, cx, |s| {
13087            s.move_with(|map, selection| {
13088                selection.collapse_to(
13089                    movement::end_of_excerpt(
13090                        map,
13091                        selection.head(),
13092                        workspace::searchable::Direction::Next,
13093                    ),
13094                    SelectionGoal::None,
13095                )
13096            });
13097        })
13098    }
13099
13100    pub fn move_to_end_of_previous_excerpt(
13101        &mut self,
13102        _: &MoveToEndOfPreviousExcerpt,
13103        window: &mut Window,
13104        cx: &mut Context<Self>,
13105    ) {
13106        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13107            cx.propagate();
13108            return;
13109        }
13110        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13111        self.change_selections(Default::default(), window, cx, |s| {
13112            s.move_with(|map, selection| {
13113                selection.collapse_to(
13114                    movement::end_of_excerpt(
13115                        map,
13116                        selection.head(),
13117                        workspace::searchable::Direction::Prev,
13118                    ),
13119                    SelectionGoal::None,
13120                )
13121            });
13122        })
13123    }
13124
13125    pub fn select_to_start_of_excerpt(
13126        &mut self,
13127        _: &SelectToStartOfExcerpt,
13128        window: &mut Window,
13129        cx: &mut Context<Self>,
13130    ) {
13131        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13132            cx.propagate();
13133            return;
13134        }
13135        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13136        self.change_selections(Default::default(), window, cx, |s| {
13137            s.move_heads_with(|map, head, _| {
13138                (
13139                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13140                    SelectionGoal::None,
13141                )
13142            });
13143        })
13144    }
13145
13146    pub fn select_to_start_of_next_excerpt(
13147        &mut self,
13148        _: &SelectToStartOfNextExcerpt,
13149        window: &mut Window,
13150        cx: &mut Context<Self>,
13151    ) {
13152        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13153            cx.propagate();
13154            return;
13155        }
13156        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13157        self.change_selections(Default::default(), window, cx, |s| {
13158            s.move_heads_with(|map, head, _| {
13159                (
13160                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13161                    SelectionGoal::None,
13162                )
13163            });
13164        })
13165    }
13166
13167    pub fn select_to_end_of_excerpt(
13168        &mut self,
13169        _: &SelectToEndOfExcerpt,
13170        window: &mut Window,
13171        cx: &mut Context<Self>,
13172    ) {
13173        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13174            cx.propagate();
13175            return;
13176        }
13177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13178        self.change_selections(Default::default(), window, cx, |s| {
13179            s.move_heads_with(|map, head, _| {
13180                (
13181                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13182                    SelectionGoal::None,
13183                )
13184            });
13185        })
13186    }
13187
13188    pub fn select_to_end_of_previous_excerpt(
13189        &mut self,
13190        _: &SelectToEndOfPreviousExcerpt,
13191        window: &mut Window,
13192        cx: &mut Context<Self>,
13193    ) {
13194        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13195            cx.propagate();
13196            return;
13197        }
13198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13199        self.change_selections(Default::default(), window, cx, |s| {
13200            s.move_heads_with(|map, head, _| {
13201                (
13202                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13203                    SelectionGoal::None,
13204                )
13205            });
13206        })
13207    }
13208
13209    pub fn move_to_beginning(
13210        &mut self,
13211        _: &MoveToBeginning,
13212        window: &mut Window,
13213        cx: &mut Context<Self>,
13214    ) {
13215        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13216            cx.propagate();
13217            return;
13218        }
13219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13220        self.change_selections(Default::default(), window, cx, |s| {
13221            s.select_ranges(vec![0..0]);
13222        });
13223    }
13224
13225    pub fn select_to_beginning(
13226        &mut self,
13227        _: &SelectToBeginning,
13228        window: &mut Window,
13229        cx: &mut Context<Self>,
13230    ) {
13231        let mut selection = self.selections.last::<Point>(cx);
13232        selection.set_head(Point::zero(), SelectionGoal::None);
13233        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13234        self.change_selections(Default::default(), window, cx, |s| {
13235            s.select(vec![selection]);
13236        });
13237    }
13238
13239    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13240        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13241            cx.propagate();
13242            return;
13243        }
13244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13245        let cursor = self.buffer.read(cx).read(cx).len();
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.select_ranges(vec![cursor..cursor])
13248        });
13249    }
13250
13251    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13252        self.nav_history = nav_history;
13253    }
13254
13255    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13256        self.nav_history.as_ref()
13257    }
13258
13259    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13260        self.push_to_nav_history(
13261            self.selections.newest_anchor().head(),
13262            None,
13263            false,
13264            true,
13265            cx,
13266        );
13267    }
13268
13269    fn push_to_nav_history(
13270        &mut self,
13271        cursor_anchor: Anchor,
13272        new_position: Option<Point>,
13273        is_deactivate: bool,
13274        always: bool,
13275        cx: &mut Context<Self>,
13276    ) {
13277        if let Some(nav_history) = self.nav_history.as_mut() {
13278            let buffer = self.buffer.read(cx).read(cx);
13279            let cursor_position = cursor_anchor.to_point(&buffer);
13280            let scroll_state = self.scroll_manager.anchor();
13281            let scroll_top_row = scroll_state.top_row(&buffer);
13282            drop(buffer);
13283
13284            if let Some(new_position) = new_position {
13285                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13286                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13287                    return;
13288                }
13289            }
13290
13291            nav_history.push(
13292                Some(NavigationData {
13293                    cursor_anchor,
13294                    cursor_position,
13295                    scroll_anchor: scroll_state,
13296                    scroll_top_row,
13297                }),
13298                cx,
13299            );
13300            cx.emit(EditorEvent::PushedToNavHistory {
13301                anchor: cursor_anchor,
13302                is_deactivate,
13303            })
13304        }
13305    }
13306
13307    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13309        let buffer = self.buffer.read(cx).snapshot(cx);
13310        let mut selection = self.selections.first::<usize>(cx);
13311        selection.set_head(buffer.len(), SelectionGoal::None);
13312        self.change_selections(Default::default(), window, cx, |s| {
13313            s.select(vec![selection]);
13314        });
13315    }
13316
13317    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13318        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13319        let end = self.buffer.read(cx).read(cx).len();
13320        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13321            s.select_ranges(vec![0..end]);
13322        });
13323    }
13324
13325    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13326        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13328        let mut selections = self.selections.all::<Point>(cx);
13329        let max_point = display_map.buffer_snapshot.max_point();
13330        for selection in &mut selections {
13331            let rows = selection.spanned_rows(true, &display_map);
13332            selection.start = Point::new(rows.start.0, 0);
13333            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13334            selection.reversed = false;
13335        }
13336        self.change_selections(Default::default(), window, cx, |s| {
13337            s.select(selections);
13338        });
13339    }
13340
13341    pub fn split_selection_into_lines(
13342        &mut self,
13343        _: &SplitSelectionIntoLines,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) {
13347        let selections = self
13348            .selections
13349            .all::<Point>(cx)
13350            .into_iter()
13351            .map(|selection| selection.start..selection.end)
13352            .collect::<Vec<_>>();
13353        self.unfold_ranges(&selections, true, true, cx);
13354
13355        let mut new_selection_ranges = Vec::new();
13356        {
13357            let buffer = self.buffer.read(cx).read(cx);
13358            for selection in selections {
13359                for row in selection.start.row..selection.end.row {
13360                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13361                    new_selection_ranges.push(cursor..cursor);
13362                }
13363
13364                let is_multiline_selection = selection.start.row != selection.end.row;
13365                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13366                // so this action feels more ergonomic when paired with other selection operations
13367                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13368                if !should_skip_last {
13369                    new_selection_ranges.push(selection.end..selection.end);
13370                }
13371            }
13372        }
13373        self.change_selections(Default::default(), window, cx, |s| {
13374            s.select_ranges(new_selection_ranges);
13375        });
13376    }
13377
13378    pub fn add_selection_above(
13379        &mut self,
13380        _: &AddSelectionAbove,
13381        window: &mut Window,
13382        cx: &mut Context<Self>,
13383    ) {
13384        self.add_selection(true, window, cx);
13385    }
13386
13387    pub fn add_selection_below(
13388        &mut self,
13389        _: &AddSelectionBelow,
13390        window: &mut Window,
13391        cx: &mut Context<Self>,
13392    ) {
13393        self.add_selection(false, window, cx);
13394    }
13395
13396    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13397        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13398
13399        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13400        let all_selections = self.selections.all::<Point>(cx);
13401        let text_layout_details = self.text_layout_details(window);
13402
13403        let (mut columnar_selections, new_selections_to_columnarize) = {
13404            if let Some(state) = self.add_selections_state.as_ref() {
13405                let columnar_selection_ids: HashSet<_> = state
13406                    .groups
13407                    .iter()
13408                    .flat_map(|group| group.stack.iter())
13409                    .copied()
13410                    .collect();
13411
13412                all_selections
13413                    .into_iter()
13414                    .partition(|s| columnar_selection_ids.contains(&s.id))
13415            } else {
13416                (Vec::new(), all_selections)
13417            }
13418        };
13419
13420        let mut state = self
13421            .add_selections_state
13422            .take()
13423            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13424
13425        for selection in new_selections_to_columnarize {
13426            let range = selection.display_range(&display_map).sorted();
13427            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13428            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13429            let positions = start_x.min(end_x)..start_x.max(end_x);
13430            let mut stack = Vec::new();
13431            for row in range.start.row().0..=range.end.row().0 {
13432                if let Some(selection) = self.selections.build_columnar_selection(
13433                    &display_map,
13434                    DisplayRow(row),
13435                    &positions,
13436                    selection.reversed,
13437                    &text_layout_details,
13438                ) {
13439                    stack.push(selection.id);
13440                    columnar_selections.push(selection);
13441                }
13442            }
13443            if !stack.is_empty() {
13444                if above {
13445                    stack.reverse();
13446                }
13447                state.groups.push(AddSelectionsGroup { above, stack });
13448            }
13449        }
13450
13451        let mut final_selections = Vec::new();
13452        let end_row = if above {
13453            DisplayRow(0)
13454        } else {
13455            display_map.max_point().row()
13456        };
13457
13458        let mut last_added_item_per_group = HashMap::default();
13459        for group in state.groups.iter_mut() {
13460            if let Some(last_id) = group.stack.last() {
13461                last_added_item_per_group.insert(*last_id, group);
13462            }
13463        }
13464
13465        for selection in columnar_selections {
13466            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13467                if above == group.above {
13468                    let range = selection.display_range(&display_map).sorted();
13469                    debug_assert_eq!(range.start.row(), range.end.row());
13470                    let mut row = range.start.row();
13471                    let positions =
13472                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13473                            px(start)..px(end)
13474                        } else {
13475                            let start_x =
13476                                display_map.x_for_display_point(range.start, &text_layout_details);
13477                            let end_x =
13478                                display_map.x_for_display_point(range.end, &text_layout_details);
13479                            start_x.min(end_x)..start_x.max(end_x)
13480                        };
13481
13482                    let mut maybe_new_selection = None;
13483                    while row != end_row {
13484                        if above {
13485                            row.0 -= 1;
13486                        } else {
13487                            row.0 += 1;
13488                        }
13489                        if let Some(new_selection) = self.selections.build_columnar_selection(
13490                            &display_map,
13491                            row,
13492                            &positions,
13493                            selection.reversed,
13494                            &text_layout_details,
13495                        ) {
13496                            maybe_new_selection = Some(new_selection);
13497                            break;
13498                        }
13499                    }
13500
13501                    if let Some(new_selection) = maybe_new_selection {
13502                        group.stack.push(new_selection.id);
13503                        if above {
13504                            final_selections.push(new_selection);
13505                            final_selections.push(selection);
13506                        } else {
13507                            final_selections.push(selection);
13508                            final_selections.push(new_selection);
13509                        }
13510                    } else {
13511                        final_selections.push(selection);
13512                    }
13513                } else {
13514                    group.stack.pop();
13515                }
13516            } else {
13517                final_selections.push(selection);
13518            }
13519        }
13520
13521        self.change_selections(Default::default(), window, cx, |s| {
13522            s.select(final_selections);
13523        });
13524
13525        let final_selection_ids: HashSet<_> = self
13526            .selections
13527            .all::<Point>(cx)
13528            .iter()
13529            .map(|s| s.id)
13530            .collect();
13531        state.groups.retain_mut(|group| {
13532            // selections might get merged above so we remove invalid items from stacks
13533            group.stack.retain(|id| final_selection_ids.contains(id));
13534
13535            // single selection in stack can be treated as initial state
13536            group.stack.len() > 1
13537        });
13538
13539        if !state.groups.is_empty() {
13540            self.add_selections_state = Some(state);
13541        }
13542    }
13543
13544    fn select_match_ranges(
13545        &mut self,
13546        range: Range<usize>,
13547        reversed: bool,
13548        replace_newest: bool,
13549        auto_scroll: Option<Autoscroll>,
13550        window: &mut Window,
13551        cx: &mut Context<Editor>,
13552    ) {
13553        self.unfold_ranges(
13554            std::slice::from_ref(&range),
13555            false,
13556            auto_scroll.is_some(),
13557            cx,
13558        );
13559        let effects = if let Some(scroll) = auto_scroll {
13560            SelectionEffects::scroll(scroll)
13561        } else {
13562            SelectionEffects::no_scroll()
13563        };
13564        self.change_selections(effects, window, cx, |s| {
13565            if replace_newest {
13566                s.delete(s.newest_anchor().id);
13567            }
13568            if reversed {
13569                s.insert_range(range.end..range.start);
13570            } else {
13571                s.insert_range(range);
13572            }
13573        });
13574    }
13575
13576    pub fn select_next_match_internal(
13577        &mut self,
13578        display_map: &DisplaySnapshot,
13579        replace_newest: bool,
13580        autoscroll: Option<Autoscroll>,
13581        window: &mut Window,
13582        cx: &mut Context<Self>,
13583    ) -> Result<()> {
13584        let buffer = &display_map.buffer_snapshot;
13585        let mut selections = self.selections.all::<usize>(cx);
13586        if let Some(mut select_next_state) = self.select_next_state.take() {
13587            let query = &select_next_state.query;
13588            if !select_next_state.done {
13589                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13590                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13591                let mut next_selected_range = None;
13592
13593                let bytes_after_last_selection =
13594                    buffer.bytes_in_range(last_selection.end..buffer.len());
13595                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13596                let query_matches = query
13597                    .stream_find_iter(bytes_after_last_selection)
13598                    .map(|result| (last_selection.end, result))
13599                    .chain(
13600                        query
13601                            .stream_find_iter(bytes_before_first_selection)
13602                            .map(|result| (0, result)),
13603                    );
13604
13605                for (start_offset, query_match) in query_matches {
13606                    let query_match = query_match.unwrap(); // can only fail due to I/O
13607                    let offset_range =
13608                        start_offset + query_match.start()..start_offset + query_match.end();
13609
13610                    if !select_next_state.wordwise
13611                        || (!buffer.is_inside_word(offset_range.start, false)
13612                            && !buffer.is_inside_word(offset_range.end, false))
13613                    {
13614                        // TODO: This is n^2, because we might check all the selections
13615                        if !selections
13616                            .iter()
13617                            .any(|selection| selection.range().overlaps(&offset_range))
13618                        {
13619                            next_selected_range = Some(offset_range);
13620                            break;
13621                        }
13622                    }
13623                }
13624
13625                if let Some(next_selected_range) = next_selected_range {
13626                    self.select_match_ranges(
13627                        next_selected_range,
13628                        last_selection.reversed,
13629                        replace_newest,
13630                        autoscroll,
13631                        window,
13632                        cx,
13633                    );
13634                } else {
13635                    select_next_state.done = true;
13636                }
13637            }
13638
13639            self.select_next_state = Some(select_next_state);
13640        } else {
13641            let mut only_carets = true;
13642            let mut same_text_selected = true;
13643            let mut selected_text = None;
13644
13645            let mut selections_iter = selections.iter().peekable();
13646            while let Some(selection) = selections_iter.next() {
13647                if selection.start != selection.end {
13648                    only_carets = false;
13649                }
13650
13651                if same_text_selected {
13652                    if selected_text.is_none() {
13653                        selected_text =
13654                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13655                    }
13656
13657                    if let Some(next_selection) = selections_iter.peek() {
13658                        if next_selection.range().len() == selection.range().len() {
13659                            let next_selected_text = buffer
13660                                .text_for_range(next_selection.range())
13661                                .collect::<String>();
13662                            if Some(next_selected_text) != selected_text {
13663                                same_text_selected = false;
13664                                selected_text = None;
13665                            }
13666                        } else {
13667                            same_text_selected = false;
13668                            selected_text = None;
13669                        }
13670                    }
13671                }
13672            }
13673
13674            if only_carets {
13675                for selection in &mut selections {
13676                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13677                    selection.start = word_range.start;
13678                    selection.end = word_range.end;
13679                    selection.goal = SelectionGoal::None;
13680                    selection.reversed = false;
13681                    self.select_match_ranges(
13682                        selection.start..selection.end,
13683                        selection.reversed,
13684                        replace_newest,
13685                        autoscroll,
13686                        window,
13687                        cx,
13688                    );
13689                }
13690
13691                if selections.len() == 1 {
13692                    let selection = selections
13693                        .last()
13694                        .expect("ensured that there's only one selection");
13695                    let query = buffer
13696                        .text_for_range(selection.start..selection.end)
13697                        .collect::<String>();
13698                    let is_empty = query.is_empty();
13699                    let select_state = SelectNextState {
13700                        query: AhoCorasick::new(&[query])?,
13701                        wordwise: true,
13702                        done: is_empty,
13703                    };
13704                    self.select_next_state = Some(select_state);
13705                } else {
13706                    self.select_next_state = None;
13707                }
13708            } else if let Some(selected_text) = selected_text {
13709                self.select_next_state = Some(SelectNextState {
13710                    query: AhoCorasick::new(&[selected_text])?,
13711                    wordwise: false,
13712                    done: false,
13713                });
13714                self.select_next_match_internal(
13715                    display_map,
13716                    replace_newest,
13717                    autoscroll,
13718                    window,
13719                    cx,
13720                )?;
13721            }
13722        }
13723        Ok(())
13724    }
13725
13726    pub fn select_all_matches(
13727        &mut self,
13728        _action: &SelectAllMatches,
13729        window: &mut Window,
13730        cx: &mut Context<Self>,
13731    ) -> Result<()> {
13732        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13733
13734        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13735
13736        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13737        let Some(select_next_state) = self.select_next_state.as_mut() else {
13738            return Ok(());
13739        };
13740        if select_next_state.done {
13741            return Ok(());
13742        }
13743
13744        let mut new_selections = Vec::new();
13745
13746        let reversed = self.selections.oldest::<usize>(cx).reversed;
13747        let buffer = &display_map.buffer_snapshot;
13748        let query_matches = select_next_state
13749            .query
13750            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13751
13752        for query_match in query_matches.into_iter() {
13753            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13754            let offset_range = if reversed {
13755                query_match.end()..query_match.start()
13756            } else {
13757                query_match.start()..query_match.end()
13758            };
13759
13760            if !select_next_state.wordwise
13761                || (!buffer.is_inside_word(offset_range.start, false)
13762                    && !buffer.is_inside_word(offset_range.end, false))
13763            {
13764                new_selections.push(offset_range.start..offset_range.end);
13765            }
13766        }
13767
13768        select_next_state.done = true;
13769
13770        if new_selections.is_empty() {
13771            log::error!("bug: new_selections is empty in select_all_matches");
13772            return Ok(());
13773        }
13774
13775        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13776        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13777            selections.select_ranges(new_selections)
13778        });
13779
13780        Ok(())
13781    }
13782
13783    pub fn select_next(
13784        &mut self,
13785        action: &SelectNext,
13786        window: &mut Window,
13787        cx: &mut Context<Self>,
13788    ) -> Result<()> {
13789        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13790        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13791        self.select_next_match_internal(
13792            &display_map,
13793            action.replace_newest,
13794            Some(Autoscroll::newest()),
13795            window,
13796            cx,
13797        )?;
13798        Ok(())
13799    }
13800
13801    pub fn select_previous(
13802        &mut self,
13803        action: &SelectPrevious,
13804        window: &mut Window,
13805        cx: &mut Context<Self>,
13806    ) -> Result<()> {
13807        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13808        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13809        let buffer = &display_map.buffer_snapshot;
13810        let mut selections = self.selections.all::<usize>(cx);
13811        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13812            let query = &select_prev_state.query;
13813            if !select_prev_state.done {
13814                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13815                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13816                let mut next_selected_range = None;
13817                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13818                let bytes_before_last_selection =
13819                    buffer.reversed_bytes_in_range(0..last_selection.start);
13820                let bytes_after_first_selection =
13821                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13822                let query_matches = query
13823                    .stream_find_iter(bytes_before_last_selection)
13824                    .map(|result| (last_selection.start, result))
13825                    .chain(
13826                        query
13827                            .stream_find_iter(bytes_after_first_selection)
13828                            .map(|result| (buffer.len(), result)),
13829                    );
13830                for (end_offset, query_match) in query_matches {
13831                    let query_match = query_match.unwrap(); // can only fail due to I/O
13832                    let offset_range =
13833                        end_offset - query_match.end()..end_offset - query_match.start();
13834
13835                    if !select_prev_state.wordwise
13836                        || (!buffer.is_inside_word(offset_range.start, false)
13837                            && !buffer.is_inside_word(offset_range.end, false))
13838                    {
13839                        next_selected_range = Some(offset_range);
13840                        break;
13841                    }
13842                }
13843
13844                if let Some(next_selected_range) = next_selected_range {
13845                    self.select_match_ranges(
13846                        next_selected_range,
13847                        last_selection.reversed,
13848                        action.replace_newest,
13849                        Some(Autoscroll::newest()),
13850                        window,
13851                        cx,
13852                    );
13853                } else {
13854                    select_prev_state.done = true;
13855                }
13856            }
13857
13858            self.select_prev_state = Some(select_prev_state);
13859        } else {
13860            let mut only_carets = true;
13861            let mut same_text_selected = true;
13862            let mut selected_text = None;
13863
13864            let mut selections_iter = selections.iter().peekable();
13865            while let Some(selection) = selections_iter.next() {
13866                if selection.start != selection.end {
13867                    only_carets = false;
13868                }
13869
13870                if same_text_selected {
13871                    if selected_text.is_none() {
13872                        selected_text =
13873                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13874                    }
13875
13876                    if let Some(next_selection) = selections_iter.peek() {
13877                        if next_selection.range().len() == selection.range().len() {
13878                            let next_selected_text = buffer
13879                                .text_for_range(next_selection.range())
13880                                .collect::<String>();
13881                            if Some(next_selected_text) != selected_text {
13882                                same_text_selected = false;
13883                                selected_text = None;
13884                            }
13885                        } else {
13886                            same_text_selected = false;
13887                            selected_text = None;
13888                        }
13889                    }
13890                }
13891            }
13892
13893            if only_carets {
13894                for selection in &mut selections {
13895                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13896                    selection.start = word_range.start;
13897                    selection.end = word_range.end;
13898                    selection.goal = SelectionGoal::None;
13899                    selection.reversed = false;
13900                    self.select_match_ranges(
13901                        selection.start..selection.end,
13902                        selection.reversed,
13903                        action.replace_newest,
13904                        Some(Autoscroll::newest()),
13905                        window,
13906                        cx,
13907                    );
13908                }
13909                if selections.len() == 1 {
13910                    let selection = selections
13911                        .last()
13912                        .expect("ensured that there's only one selection");
13913                    let query = buffer
13914                        .text_for_range(selection.start..selection.end)
13915                        .collect::<String>();
13916                    let is_empty = query.is_empty();
13917                    let select_state = SelectNextState {
13918                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13919                        wordwise: true,
13920                        done: is_empty,
13921                    };
13922                    self.select_prev_state = Some(select_state);
13923                } else {
13924                    self.select_prev_state = None;
13925                }
13926            } else if let Some(selected_text) = selected_text {
13927                self.select_prev_state = Some(SelectNextState {
13928                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13929                    wordwise: false,
13930                    done: false,
13931                });
13932                self.select_previous(action, window, cx)?;
13933            }
13934        }
13935        Ok(())
13936    }
13937
13938    pub fn find_next_match(
13939        &mut self,
13940        _: &FindNextMatch,
13941        window: &mut Window,
13942        cx: &mut Context<Self>,
13943    ) -> Result<()> {
13944        let selections = self.selections.disjoint_anchors();
13945        match selections.first() {
13946            Some(first) if selections.len() >= 2 => {
13947                self.change_selections(Default::default(), window, cx, |s| {
13948                    s.select_ranges([first.range()]);
13949                });
13950            }
13951            _ => self.select_next(
13952                &SelectNext {
13953                    replace_newest: true,
13954                },
13955                window,
13956                cx,
13957            )?,
13958        }
13959        Ok(())
13960    }
13961
13962    pub fn find_previous_match(
13963        &mut self,
13964        _: &FindPreviousMatch,
13965        window: &mut Window,
13966        cx: &mut Context<Self>,
13967    ) -> Result<()> {
13968        let selections = self.selections.disjoint_anchors();
13969        match selections.last() {
13970            Some(last) if selections.len() >= 2 => {
13971                self.change_selections(Default::default(), window, cx, |s| {
13972                    s.select_ranges([last.range()]);
13973                });
13974            }
13975            _ => self.select_previous(
13976                &SelectPrevious {
13977                    replace_newest: true,
13978                },
13979                window,
13980                cx,
13981            )?,
13982        }
13983        Ok(())
13984    }
13985
13986    pub fn toggle_comments(
13987        &mut self,
13988        action: &ToggleComments,
13989        window: &mut Window,
13990        cx: &mut Context<Self>,
13991    ) {
13992        if self.read_only(cx) {
13993            return;
13994        }
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13996        let text_layout_details = &self.text_layout_details(window);
13997        self.transact(window, cx, |this, window, cx| {
13998            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13999            let mut edits = Vec::new();
14000            let mut selection_edit_ranges = Vec::new();
14001            let mut last_toggled_row = None;
14002            let snapshot = this.buffer.read(cx).read(cx);
14003            let empty_str: Arc<str> = Arc::default();
14004            let mut suffixes_inserted = Vec::new();
14005            let ignore_indent = action.ignore_indent;
14006
14007            fn comment_prefix_range(
14008                snapshot: &MultiBufferSnapshot,
14009                row: MultiBufferRow,
14010                comment_prefix: &str,
14011                comment_prefix_whitespace: &str,
14012                ignore_indent: bool,
14013            ) -> Range<Point> {
14014                let indent_size = if ignore_indent {
14015                    0
14016                } else {
14017                    snapshot.indent_size_for_line(row).len
14018                };
14019
14020                let start = Point::new(row.0, indent_size);
14021
14022                let mut line_bytes = snapshot
14023                    .bytes_in_range(start..snapshot.max_point())
14024                    .flatten()
14025                    .copied();
14026
14027                // If this line currently begins with the line comment prefix, then record
14028                // the range containing the prefix.
14029                if line_bytes
14030                    .by_ref()
14031                    .take(comment_prefix.len())
14032                    .eq(comment_prefix.bytes())
14033                {
14034                    // Include any whitespace that matches the comment prefix.
14035                    let matching_whitespace_len = line_bytes
14036                        .zip(comment_prefix_whitespace.bytes())
14037                        .take_while(|(a, b)| a == b)
14038                        .count() as u32;
14039                    let end = Point::new(
14040                        start.row,
14041                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14042                    );
14043                    start..end
14044                } else {
14045                    start..start
14046                }
14047            }
14048
14049            fn comment_suffix_range(
14050                snapshot: &MultiBufferSnapshot,
14051                row: MultiBufferRow,
14052                comment_suffix: &str,
14053                comment_suffix_has_leading_space: bool,
14054            ) -> Range<Point> {
14055                let end = Point::new(row.0, snapshot.line_len(row));
14056                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14057
14058                let mut line_end_bytes = snapshot
14059                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14060                    .flatten()
14061                    .copied();
14062
14063                let leading_space_len = if suffix_start_column > 0
14064                    && line_end_bytes.next() == Some(b' ')
14065                    && comment_suffix_has_leading_space
14066                {
14067                    1
14068                } else {
14069                    0
14070                };
14071
14072                // If this line currently begins with the line comment prefix, then record
14073                // the range containing the prefix.
14074                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14075                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14076                    start..end
14077                } else {
14078                    end..end
14079                }
14080            }
14081
14082            // TODO: Handle selections that cross excerpts
14083            for selection in &mut selections {
14084                let start_column = snapshot
14085                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14086                    .len;
14087                let language = if let Some(language) =
14088                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14089                {
14090                    language
14091                } else {
14092                    continue;
14093                };
14094
14095                selection_edit_ranges.clear();
14096
14097                // If multiple selections contain a given row, avoid processing that
14098                // row more than once.
14099                let mut start_row = MultiBufferRow(selection.start.row);
14100                if last_toggled_row == Some(start_row) {
14101                    start_row = start_row.next_row();
14102                }
14103                let end_row =
14104                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14105                        MultiBufferRow(selection.end.row - 1)
14106                    } else {
14107                        MultiBufferRow(selection.end.row)
14108                    };
14109                last_toggled_row = Some(end_row);
14110
14111                if start_row > end_row {
14112                    continue;
14113                }
14114
14115                // If the language has line comments, toggle those.
14116                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14117
14118                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14119                if ignore_indent {
14120                    full_comment_prefixes = full_comment_prefixes
14121                        .into_iter()
14122                        .map(|s| Arc::from(s.trim_end()))
14123                        .collect();
14124                }
14125
14126                if !full_comment_prefixes.is_empty() {
14127                    let first_prefix = full_comment_prefixes
14128                        .first()
14129                        .expect("prefixes is non-empty");
14130                    let prefix_trimmed_lengths = full_comment_prefixes
14131                        .iter()
14132                        .map(|p| p.trim_end_matches(' ').len())
14133                        .collect::<SmallVec<[usize; 4]>>();
14134
14135                    let mut all_selection_lines_are_comments = true;
14136
14137                    for row in start_row.0..=end_row.0 {
14138                        let row = MultiBufferRow(row);
14139                        if start_row < end_row && snapshot.is_line_blank(row) {
14140                            continue;
14141                        }
14142
14143                        let prefix_range = full_comment_prefixes
14144                            .iter()
14145                            .zip(prefix_trimmed_lengths.iter().copied())
14146                            .map(|(prefix, trimmed_prefix_len)| {
14147                                comment_prefix_range(
14148                                    snapshot.deref(),
14149                                    row,
14150                                    &prefix[..trimmed_prefix_len],
14151                                    &prefix[trimmed_prefix_len..],
14152                                    ignore_indent,
14153                                )
14154                            })
14155                            .max_by_key(|range| range.end.column - range.start.column)
14156                            .expect("prefixes is non-empty");
14157
14158                        if prefix_range.is_empty() {
14159                            all_selection_lines_are_comments = false;
14160                        }
14161
14162                        selection_edit_ranges.push(prefix_range);
14163                    }
14164
14165                    if all_selection_lines_are_comments {
14166                        edits.extend(
14167                            selection_edit_ranges
14168                                .iter()
14169                                .cloned()
14170                                .map(|range| (range, empty_str.clone())),
14171                        );
14172                    } else {
14173                        let min_column = selection_edit_ranges
14174                            .iter()
14175                            .map(|range| range.start.column)
14176                            .min()
14177                            .unwrap_or(0);
14178                        edits.extend(selection_edit_ranges.iter().map(|range| {
14179                            let position = Point::new(range.start.row, min_column);
14180                            (position..position, first_prefix.clone())
14181                        }));
14182                    }
14183                } else if let Some((full_comment_prefix, comment_suffix)) =
14184                    language.block_comment_delimiters()
14185                {
14186                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14187                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14188                    let prefix_range = comment_prefix_range(
14189                        snapshot.deref(),
14190                        start_row,
14191                        comment_prefix,
14192                        comment_prefix_whitespace,
14193                        ignore_indent,
14194                    );
14195                    let suffix_range = comment_suffix_range(
14196                        snapshot.deref(),
14197                        end_row,
14198                        comment_suffix.trim_start_matches(' '),
14199                        comment_suffix.starts_with(' '),
14200                    );
14201
14202                    if prefix_range.is_empty() || suffix_range.is_empty() {
14203                        edits.push((
14204                            prefix_range.start..prefix_range.start,
14205                            full_comment_prefix.clone(),
14206                        ));
14207                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14208                        suffixes_inserted.push((end_row, comment_suffix.len()));
14209                    } else {
14210                        edits.push((prefix_range, empty_str.clone()));
14211                        edits.push((suffix_range, empty_str.clone()));
14212                    }
14213                } else {
14214                    continue;
14215                }
14216            }
14217
14218            drop(snapshot);
14219            this.buffer.update(cx, |buffer, cx| {
14220                buffer.edit(edits, None, cx);
14221            });
14222
14223            // Adjust selections so that they end before any comment suffixes that
14224            // were inserted.
14225            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14226            let mut selections = this.selections.all::<Point>(cx);
14227            let snapshot = this.buffer.read(cx).read(cx);
14228            for selection in &mut selections {
14229                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14230                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14231                        Ordering::Less => {
14232                            suffixes_inserted.next();
14233                            continue;
14234                        }
14235                        Ordering::Greater => break,
14236                        Ordering::Equal => {
14237                            if selection.end.column == snapshot.line_len(row) {
14238                                if selection.is_empty() {
14239                                    selection.start.column -= suffix_len as u32;
14240                                }
14241                                selection.end.column -= suffix_len as u32;
14242                            }
14243                            break;
14244                        }
14245                    }
14246                }
14247            }
14248
14249            drop(snapshot);
14250            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14251
14252            let selections = this.selections.all::<Point>(cx);
14253            let selections_on_single_row = selections.windows(2).all(|selections| {
14254                selections[0].start.row == selections[1].start.row
14255                    && selections[0].end.row == selections[1].end.row
14256                    && selections[0].start.row == selections[0].end.row
14257            });
14258            let selections_selecting = selections
14259                .iter()
14260                .any(|selection| selection.start != selection.end);
14261            let advance_downwards = action.advance_downwards
14262                && selections_on_single_row
14263                && !selections_selecting
14264                && !matches!(this.mode, EditorMode::SingleLine { .. });
14265
14266            if advance_downwards {
14267                let snapshot = this.buffer.read(cx).snapshot(cx);
14268
14269                this.change_selections(Default::default(), window, cx, |s| {
14270                    s.move_cursors_with(|display_snapshot, display_point, _| {
14271                        let mut point = display_point.to_point(display_snapshot);
14272                        point.row += 1;
14273                        point = snapshot.clip_point(point, Bias::Left);
14274                        let display_point = point.to_display_point(display_snapshot);
14275                        let goal = SelectionGoal::HorizontalPosition(
14276                            display_snapshot
14277                                .x_for_display_point(display_point, text_layout_details)
14278                                .into(),
14279                        );
14280                        (display_point, goal)
14281                    })
14282                });
14283            }
14284        });
14285    }
14286
14287    pub fn select_enclosing_symbol(
14288        &mut self,
14289        _: &SelectEnclosingSymbol,
14290        window: &mut Window,
14291        cx: &mut Context<Self>,
14292    ) {
14293        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14294
14295        let buffer = self.buffer.read(cx).snapshot(cx);
14296        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14297
14298        fn update_selection(
14299            selection: &Selection<usize>,
14300            buffer_snap: &MultiBufferSnapshot,
14301        ) -> Option<Selection<usize>> {
14302            let cursor = selection.head();
14303            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14304            for symbol in symbols.iter().rev() {
14305                let start = symbol.range.start.to_offset(buffer_snap);
14306                let end = symbol.range.end.to_offset(buffer_snap);
14307                let new_range = start..end;
14308                if start < selection.start || end > selection.end {
14309                    return Some(Selection {
14310                        id: selection.id,
14311                        start: new_range.start,
14312                        end: new_range.end,
14313                        goal: SelectionGoal::None,
14314                        reversed: selection.reversed,
14315                    });
14316                }
14317            }
14318            None
14319        }
14320
14321        let mut selected_larger_symbol = false;
14322        let new_selections = old_selections
14323            .iter()
14324            .map(|selection| match update_selection(selection, &buffer) {
14325                Some(new_selection) => {
14326                    if new_selection.range() != selection.range() {
14327                        selected_larger_symbol = true;
14328                    }
14329                    new_selection
14330                }
14331                None => selection.clone(),
14332            })
14333            .collect::<Vec<_>>();
14334
14335        if selected_larger_symbol {
14336            self.change_selections(Default::default(), window, cx, |s| {
14337                s.select(new_selections);
14338            });
14339        }
14340    }
14341
14342    pub fn select_larger_syntax_node(
14343        &mut self,
14344        _: &SelectLargerSyntaxNode,
14345        window: &mut Window,
14346        cx: &mut Context<Self>,
14347    ) {
14348        let Some(visible_row_count) = self.visible_row_count() else {
14349            return;
14350        };
14351        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14352        if old_selections.is_empty() {
14353            return;
14354        }
14355
14356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14357
14358        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14359        let buffer = self.buffer.read(cx).snapshot(cx);
14360
14361        let mut selected_larger_node = false;
14362        let mut new_selections = old_selections
14363            .iter()
14364            .map(|selection| {
14365                let old_range = selection.start..selection.end;
14366
14367                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14368                    // manually select word at selection
14369                    if ["string_content", "inline"].contains(&node.kind()) {
14370                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14371                        // ignore if word is already selected
14372                        if !word_range.is_empty() && old_range != word_range {
14373                            let (last_word_range, _) =
14374                                buffer.surrounding_word(old_range.end, false);
14375                            // only select word if start and end point belongs to same word
14376                            if word_range == last_word_range {
14377                                selected_larger_node = true;
14378                                return Selection {
14379                                    id: selection.id,
14380                                    start: word_range.start,
14381                                    end: word_range.end,
14382                                    goal: SelectionGoal::None,
14383                                    reversed: selection.reversed,
14384                                };
14385                            }
14386                        }
14387                    }
14388                }
14389
14390                let mut new_range = old_range.clone();
14391                while let Some((_node, containing_range)) =
14392                    buffer.syntax_ancestor(new_range.clone())
14393                {
14394                    new_range = match containing_range {
14395                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14396                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14397                    };
14398                    if !display_map.intersects_fold(new_range.start)
14399                        && !display_map.intersects_fold(new_range.end)
14400                    {
14401                        break;
14402                    }
14403                }
14404
14405                selected_larger_node |= new_range != old_range;
14406                Selection {
14407                    id: selection.id,
14408                    start: new_range.start,
14409                    end: new_range.end,
14410                    goal: SelectionGoal::None,
14411                    reversed: selection.reversed,
14412                }
14413            })
14414            .collect::<Vec<_>>();
14415
14416        if !selected_larger_node {
14417            return; // don't put this call in the history
14418        }
14419
14420        // scroll based on transformation done to the last selection created by the user
14421        let (last_old, last_new) = old_selections
14422            .last()
14423            .zip(new_selections.last().cloned())
14424            .expect("old_selections isn't empty");
14425
14426        // revert selection
14427        let is_selection_reversed = {
14428            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14429            new_selections.last_mut().expect("checked above").reversed =
14430                should_newest_selection_be_reversed;
14431            should_newest_selection_be_reversed
14432        };
14433
14434        if selected_larger_node {
14435            self.select_syntax_node_history.disable_clearing = true;
14436            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14437                s.select(new_selections.clone());
14438            });
14439            self.select_syntax_node_history.disable_clearing = false;
14440        }
14441
14442        let start_row = last_new.start.to_display_point(&display_map).row().0;
14443        let end_row = last_new.end.to_display_point(&display_map).row().0;
14444        let selection_height = end_row - start_row + 1;
14445        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14446
14447        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14448        let scroll_behavior = if fits_on_the_screen {
14449            self.request_autoscroll(Autoscroll::fit(), cx);
14450            SelectSyntaxNodeScrollBehavior::FitSelection
14451        } else if is_selection_reversed {
14452            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14453            SelectSyntaxNodeScrollBehavior::CursorTop
14454        } else {
14455            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14456            SelectSyntaxNodeScrollBehavior::CursorBottom
14457        };
14458
14459        self.select_syntax_node_history.push((
14460            old_selections,
14461            scroll_behavior,
14462            is_selection_reversed,
14463        ));
14464    }
14465
14466    pub fn select_smaller_syntax_node(
14467        &mut self,
14468        _: &SelectSmallerSyntaxNode,
14469        window: &mut Window,
14470        cx: &mut Context<Self>,
14471    ) {
14472        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14473
14474        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14475            self.select_syntax_node_history.pop()
14476        {
14477            if let Some(selection) = selections.last_mut() {
14478                selection.reversed = is_selection_reversed;
14479            }
14480
14481            self.select_syntax_node_history.disable_clearing = true;
14482            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14483                s.select(selections.to_vec());
14484            });
14485            self.select_syntax_node_history.disable_clearing = false;
14486
14487            match scroll_behavior {
14488                SelectSyntaxNodeScrollBehavior::CursorTop => {
14489                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14490                }
14491                SelectSyntaxNodeScrollBehavior::FitSelection => {
14492                    self.request_autoscroll(Autoscroll::fit(), cx);
14493                }
14494                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14495                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14496                }
14497            }
14498        }
14499    }
14500
14501    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14502        if !EditorSettings::get_global(cx).gutter.runnables {
14503            self.clear_tasks();
14504            return Task::ready(());
14505        }
14506        let project = self.project.as_ref().map(Entity::downgrade);
14507        let task_sources = self.lsp_task_sources(cx);
14508        let multi_buffer = self.buffer.downgrade();
14509        cx.spawn_in(window, async move |editor, cx| {
14510            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14511            let Some(project) = project.and_then(|p| p.upgrade()) else {
14512                return;
14513            };
14514            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14515                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14516            }) else {
14517                return;
14518            };
14519
14520            let hide_runnables = project
14521                .update(cx, |project, cx| {
14522                    // Do not display any test indicators in non-dev server remote projects.
14523                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14524                })
14525                .unwrap_or(true);
14526            if hide_runnables {
14527                return;
14528            }
14529            let new_rows =
14530                cx.background_spawn({
14531                    let snapshot = display_snapshot.clone();
14532                    async move {
14533                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14534                    }
14535                })
14536                    .await;
14537            let Ok(lsp_tasks) =
14538                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14539            else {
14540                return;
14541            };
14542            let lsp_tasks = lsp_tasks.await;
14543
14544            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14545                lsp_tasks
14546                    .into_iter()
14547                    .flat_map(|(kind, tasks)| {
14548                        tasks.into_iter().filter_map(move |(location, task)| {
14549                            Some((kind.clone(), location?, task))
14550                        })
14551                    })
14552                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14553                        let buffer = location.target.buffer;
14554                        let buffer_snapshot = buffer.read(cx).snapshot();
14555                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14556                            |(excerpt_id, snapshot, _)| {
14557                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14558                                    display_snapshot
14559                                        .buffer_snapshot
14560                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14561                                } else {
14562                                    None
14563                                }
14564                            },
14565                        );
14566                        if let Some(offset) = offset {
14567                            let task_buffer_range =
14568                                location.target.range.to_point(&buffer_snapshot);
14569                            let context_buffer_range =
14570                                task_buffer_range.to_offset(&buffer_snapshot);
14571                            let context_range = BufferOffset(context_buffer_range.start)
14572                                ..BufferOffset(context_buffer_range.end);
14573
14574                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14575                                .or_insert_with(|| RunnableTasks {
14576                                    templates: Vec::new(),
14577                                    offset,
14578                                    column: task_buffer_range.start.column,
14579                                    extra_variables: HashMap::default(),
14580                                    context_range,
14581                                })
14582                                .templates
14583                                .push((kind, task.original_task().clone()));
14584                        }
14585
14586                        acc
14587                    })
14588            }) else {
14589                return;
14590            };
14591
14592            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14593                buffer.language_settings(cx).tasks.prefer_lsp
14594            }) else {
14595                return;
14596            };
14597
14598            let rows = Self::runnable_rows(
14599                project,
14600                display_snapshot,
14601                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14602                new_rows,
14603                cx.clone(),
14604            )
14605            .await;
14606            editor
14607                .update(cx, |editor, _| {
14608                    editor.clear_tasks();
14609                    for (key, mut value) in rows {
14610                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14611                            value.templates.extend(lsp_tasks.templates);
14612                        }
14613
14614                        editor.insert_tasks(key, value);
14615                    }
14616                    for (key, value) in lsp_tasks_by_rows {
14617                        editor.insert_tasks(key, value);
14618                    }
14619                })
14620                .ok();
14621        })
14622    }
14623    fn fetch_runnable_ranges(
14624        snapshot: &DisplaySnapshot,
14625        range: Range<Anchor>,
14626    ) -> Vec<language::RunnableRange> {
14627        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14628    }
14629
14630    fn runnable_rows(
14631        project: Entity<Project>,
14632        snapshot: DisplaySnapshot,
14633        prefer_lsp: bool,
14634        runnable_ranges: Vec<RunnableRange>,
14635        cx: AsyncWindowContext,
14636    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14637        cx.spawn(async move |cx| {
14638            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14639            for mut runnable in runnable_ranges {
14640                let Some(tasks) = cx
14641                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14642                    .ok()
14643                else {
14644                    continue;
14645                };
14646                let mut tasks = tasks.await;
14647
14648                if prefer_lsp {
14649                    tasks.retain(|(task_kind, _)| {
14650                        !matches!(task_kind, TaskSourceKind::Language { .. })
14651                    });
14652                }
14653                if tasks.is_empty() {
14654                    continue;
14655                }
14656
14657                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14658                let Some(row) = snapshot
14659                    .buffer_snapshot
14660                    .buffer_line_for_row(MultiBufferRow(point.row))
14661                    .map(|(_, range)| range.start.row)
14662                else {
14663                    continue;
14664                };
14665
14666                let context_range =
14667                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14668                runnable_rows.push((
14669                    (runnable.buffer_id, row),
14670                    RunnableTasks {
14671                        templates: tasks,
14672                        offset: snapshot
14673                            .buffer_snapshot
14674                            .anchor_before(runnable.run_range.start),
14675                        context_range,
14676                        column: point.column,
14677                        extra_variables: runnable.extra_captures,
14678                    },
14679                ));
14680            }
14681            runnable_rows
14682        })
14683    }
14684
14685    fn templates_with_tags(
14686        project: &Entity<Project>,
14687        runnable: &mut Runnable,
14688        cx: &mut App,
14689    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14690        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14691            let (worktree_id, file) = project
14692                .buffer_for_id(runnable.buffer, cx)
14693                .and_then(|buffer| buffer.read(cx).file())
14694                .map(|file| (file.worktree_id(cx), file.clone()))
14695                .unzip();
14696
14697            (
14698                project.task_store().read(cx).task_inventory().cloned(),
14699                worktree_id,
14700                file,
14701            )
14702        });
14703
14704        let tags = mem::take(&mut runnable.tags);
14705        let language = runnable.language.clone();
14706        cx.spawn(async move |cx| {
14707            let mut templates_with_tags = Vec::new();
14708            if let Some(inventory) = inventory {
14709                for RunnableTag(tag) in tags {
14710                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14711                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14712                    }) else {
14713                        return templates_with_tags;
14714                    };
14715                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14716                        move |(_, template)| {
14717                            template.tags.iter().any(|source_tag| source_tag == &tag)
14718                        },
14719                    ));
14720                }
14721            }
14722            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14723
14724            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14725                // Strongest source wins; if we have worktree tag binding, prefer that to
14726                // global and language bindings;
14727                // if we have a global binding, prefer that to language binding.
14728                let first_mismatch = templates_with_tags
14729                    .iter()
14730                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14731                if let Some(index) = first_mismatch {
14732                    templates_with_tags.truncate(index);
14733                }
14734            }
14735
14736            templates_with_tags
14737        })
14738    }
14739
14740    pub fn move_to_enclosing_bracket(
14741        &mut self,
14742        _: &MoveToEnclosingBracket,
14743        window: &mut Window,
14744        cx: &mut Context<Self>,
14745    ) {
14746        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14747        self.change_selections(Default::default(), window, cx, |s| {
14748            s.move_offsets_with(|snapshot, selection| {
14749                let Some(enclosing_bracket_ranges) =
14750                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14751                else {
14752                    return;
14753                };
14754
14755                let mut best_length = usize::MAX;
14756                let mut best_inside = false;
14757                let mut best_in_bracket_range = false;
14758                let mut best_destination = None;
14759                for (open, close) in enclosing_bracket_ranges {
14760                    let close = close.to_inclusive();
14761                    let length = close.end() - open.start;
14762                    let inside = selection.start >= open.end && selection.end <= *close.start();
14763                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14764                        || close.contains(&selection.head());
14765
14766                    // If best is next to a bracket and current isn't, skip
14767                    if !in_bracket_range && best_in_bracket_range {
14768                        continue;
14769                    }
14770
14771                    // Prefer smaller lengths unless best is inside and current isn't
14772                    if length > best_length && (best_inside || !inside) {
14773                        continue;
14774                    }
14775
14776                    best_length = length;
14777                    best_inside = inside;
14778                    best_in_bracket_range = in_bracket_range;
14779                    best_destination = Some(
14780                        if close.contains(&selection.start) && close.contains(&selection.end) {
14781                            if inside { open.end } else { open.start }
14782                        } else if inside {
14783                            *close.start()
14784                        } else {
14785                            *close.end()
14786                        },
14787                    );
14788                }
14789
14790                if let Some(destination) = best_destination {
14791                    selection.collapse_to(destination, SelectionGoal::None);
14792                }
14793            })
14794        });
14795    }
14796
14797    pub fn undo_selection(
14798        &mut self,
14799        _: &UndoSelection,
14800        window: &mut Window,
14801        cx: &mut Context<Self>,
14802    ) {
14803        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14804        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14805            self.selection_history.mode = SelectionHistoryMode::Undoing;
14806            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14807                this.end_selection(window, cx);
14808                this.change_selections(
14809                    SelectionEffects::scroll(Autoscroll::newest()),
14810                    window,
14811                    cx,
14812                    |s| s.select_anchors(entry.selections.to_vec()),
14813                );
14814            });
14815            self.selection_history.mode = SelectionHistoryMode::Normal;
14816
14817            self.select_next_state = entry.select_next_state;
14818            self.select_prev_state = entry.select_prev_state;
14819            self.add_selections_state = entry.add_selections_state;
14820        }
14821    }
14822
14823    pub fn redo_selection(
14824        &mut self,
14825        _: &RedoSelection,
14826        window: &mut Window,
14827        cx: &mut Context<Self>,
14828    ) {
14829        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14830        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14831            self.selection_history.mode = SelectionHistoryMode::Redoing;
14832            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14833                this.end_selection(window, cx);
14834                this.change_selections(
14835                    SelectionEffects::scroll(Autoscroll::newest()),
14836                    window,
14837                    cx,
14838                    |s| s.select_anchors(entry.selections.to_vec()),
14839                );
14840            });
14841            self.selection_history.mode = SelectionHistoryMode::Normal;
14842
14843            self.select_next_state = entry.select_next_state;
14844            self.select_prev_state = entry.select_prev_state;
14845            self.add_selections_state = entry.add_selections_state;
14846        }
14847    }
14848
14849    pub fn expand_excerpts(
14850        &mut self,
14851        action: &ExpandExcerpts,
14852        _: &mut Window,
14853        cx: &mut Context<Self>,
14854    ) {
14855        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14856    }
14857
14858    pub fn expand_excerpts_down(
14859        &mut self,
14860        action: &ExpandExcerptsDown,
14861        _: &mut Window,
14862        cx: &mut Context<Self>,
14863    ) {
14864        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14865    }
14866
14867    pub fn expand_excerpts_up(
14868        &mut self,
14869        action: &ExpandExcerptsUp,
14870        _: &mut Window,
14871        cx: &mut Context<Self>,
14872    ) {
14873        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14874    }
14875
14876    pub fn expand_excerpts_for_direction(
14877        &mut self,
14878        lines: u32,
14879        direction: ExpandExcerptDirection,
14880
14881        cx: &mut Context<Self>,
14882    ) {
14883        let selections = self.selections.disjoint_anchors();
14884
14885        let lines = if lines == 0 {
14886            EditorSettings::get_global(cx).expand_excerpt_lines
14887        } else {
14888            lines
14889        };
14890
14891        self.buffer.update(cx, |buffer, cx| {
14892            let snapshot = buffer.snapshot(cx);
14893            let mut excerpt_ids = selections
14894                .iter()
14895                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14896                .collect::<Vec<_>>();
14897            excerpt_ids.sort();
14898            excerpt_ids.dedup();
14899            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14900        })
14901    }
14902
14903    pub fn expand_excerpt(
14904        &mut self,
14905        excerpt: ExcerptId,
14906        direction: ExpandExcerptDirection,
14907        window: &mut Window,
14908        cx: &mut Context<Self>,
14909    ) {
14910        let current_scroll_position = self.scroll_position(cx);
14911        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14912        let mut should_scroll_up = false;
14913
14914        if direction == ExpandExcerptDirection::Down {
14915            let multi_buffer = self.buffer.read(cx);
14916            let snapshot = multi_buffer.snapshot(cx);
14917            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14918                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14919                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14920                        let buffer_snapshot = buffer.read(cx).snapshot();
14921                        let excerpt_end_row =
14922                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14923                        let last_row = buffer_snapshot.max_point().row;
14924                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14925                        should_scroll_up = lines_below >= lines_to_expand;
14926                    }
14927                }
14928            }
14929        }
14930
14931        self.buffer.update(cx, |buffer, cx| {
14932            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14933        });
14934
14935        if should_scroll_up {
14936            let new_scroll_position =
14937                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14938            self.set_scroll_position(new_scroll_position, window, cx);
14939        }
14940    }
14941
14942    pub fn go_to_singleton_buffer_point(
14943        &mut self,
14944        point: Point,
14945        window: &mut Window,
14946        cx: &mut Context<Self>,
14947    ) {
14948        self.go_to_singleton_buffer_range(point..point, window, cx);
14949    }
14950
14951    pub fn go_to_singleton_buffer_range(
14952        &mut self,
14953        range: Range<Point>,
14954        window: &mut Window,
14955        cx: &mut Context<Self>,
14956    ) {
14957        let multibuffer = self.buffer().read(cx);
14958        let Some(buffer) = multibuffer.as_singleton() else {
14959            return;
14960        };
14961        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14962            return;
14963        };
14964        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14965            return;
14966        };
14967        self.change_selections(
14968            SelectionEffects::default().nav_history(true),
14969            window,
14970            cx,
14971            |s| s.select_anchor_ranges([start..end]),
14972        );
14973    }
14974
14975    pub fn go_to_diagnostic(
14976        &mut self,
14977        _: &GoToDiagnostic,
14978        window: &mut Window,
14979        cx: &mut Context<Self>,
14980    ) {
14981        if !self.diagnostics_enabled() {
14982            return;
14983        }
14984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14985        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14986    }
14987
14988    pub fn go_to_prev_diagnostic(
14989        &mut self,
14990        _: &GoToPreviousDiagnostic,
14991        window: &mut Window,
14992        cx: &mut Context<Self>,
14993    ) {
14994        if !self.diagnostics_enabled() {
14995            return;
14996        }
14997        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14998        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14999    }
15000
15001    pub fn go_to_diagnostic_impl(
15002        &mut self,
15003        direction: Direction,
15004        window: &mut Window,
15005        cx: &mut Context<Self>,
15006    ) {
15007        let buffer = self.buffer.read(cx).snapshot(cx);
15008        let selection = self.selections.newest::<usize>(cx);
15009
15010        let mut active_group_id = None;
15011        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15012            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15013                active_group_id = Some(active_group.group_id);
15014            }
15015        }
15016
15017        fn filtered(
15018            snapshot: EditorSnapshot,
15019            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15020        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15021            diagnostics
15022                .filter(|entry| entry.range.start != entry.range.end)
15023                .filter(|entry| !entry.diagnostic.is_unnecessary)
15024                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15025        }
15026
15027        let snapshot = self.snapshot(window, cx);
15028        let before = filtered(
15029            snapshot.clone(),
15030            buffer
15031                .diagnostics_in_range(0..selection.start)
15032                .filter(|entry| entry.range.start <= selection.start),
15033        );
15034        let after = filtered(
15035            snapshot,
15036            buffer
15037                .diagnostics_in_range(selection.start..buffer.len())
15038                .filter(|entry| entry.range.start >= selection.start),
15039        );
15040
15041        let mut found: Option<DiagnosticEntry<usize>> = None;
15042        if direction == Direction::Prev {
15043            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15044            {
15045                for diagnostic in prev_diagnostics.into_iter().rev() {
15046                    if diagnostic.range.start != selection.start
15047                        || active_group_id
15048                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15049                    {
15050                        found = Some(diagnostic);
15051                        break 'outer;
15052                    }
15053                }
15054            }
15055        } else {
15056            for diagnostic in after.chain(before) {
15057                if diagnostic.range.start != selection.start
15058                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15059                {
15060                    found = Some(diagnostic);
15061                    break;
15062                }
15063            }
15064        }
15065        let Some(next_diagnostic) = found else {
15066            return;
15067        };
15068
15069        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15070            return;
15071        };
15072        self.change_selections(Default::default(), window, cx, |s| {
15073            s.select_ranges(vec![
15074                next_diagnostic.range.start..next_diagnostic.range.start,
15075            ])
15076        });
15077        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15078        self.refresh_inline_completion(false, true, window, cx);
15079    }
15080
15081    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15083        let snapshot = self.snapshot(window, cx);
15084        let selection = self.selections.newest::<Point>(cx);
15085        self.go_to_hunk_before_or_after_position(
15086            &snapshot,
15087            selection.head(),
15088            Direction::Next,
15089            window,
15090            cx,
15091        );
15092    }
15093
15094    pub fn go_to_hunk_before_or_after_position(
15095        &mut self,
15096        snapshot: &EditorSnapshot,
15097        position: Point,
15098        direction: Direction,
15099        window: &mut Window,
15100        cx: &mut Context<Editor>,
15101    ) {
15102        let row = if direction == Direction::Next {
15103            self.hunk_after_position(snapshot, position)
15104                .map(|hunk| hunk.row_range.start)
15105        } else {
15106            self.hunk_before_position(snapshot, position)
15107        };
15108
15109        if let Some(row) = row {
15110            let destination = Point::new(row.0, 0);
15111            let autoscroll = Autoscroll::center();
15112
15113            self.unfold_ranges(&[destination..destination], false, false, cx);
15114            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15115                s.select_ranges([destination..destination]);
15116            });
15117        }
15118    }
15119
15120    fn hunk_after_position(
15121        &mut self,
15122        snapshot: &EditorSnapshot,
15123        position: Point,
15124    ) -> Option<MultiBufferDiffHunk> {
15125        snapshot
15126            .buffer_snapshot
15127            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15128            .find(|hunk| hunk.row_range.start.0 > position.row)
15129            .or_else(|| {
15130                snapshot
15131                    .buffer_snapshot
15132                    .diff_hunks_in_range(Point::zero()..position)
15133                    .find(|hunk| hunk.row_range.end.0 < position.row)
15134            })
15135    }
15136
15137    fn go_to_prev_hunk(
15138        &mut self,
15139        _: &GoToPreviousHunk,
15140        window: &mut Window,
15141        cx: &mut Context<Self>,
15142    ) {
15143        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15144        let snapshot = self.snapshot(window, cx);
15145        let selection = self.selections.newest::<Point>(cx);
15146        self.go_to_hunk_before_or_after_position(
15147            &snapshot,
15148            selection.head(),
15149            Direction::Prev,
15150            window,
15151            cx,
15152        );
15153    }
15154
15155    fn hunk_before_position(
15156        &mut self,
15157        snapshot: &EditorSnapshot,
15158        position: Point,
15159    ) -> Option<MultiBufferRow> {
15160        snapshot
15161            .buffer_snapshot
15162            .diff_hunk_before(position)
15163            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15164    }
15165
15166    fn go_to_next_change(
15167        &mut self,
15168        _: &GoToNextChange,
15169        window: &mut Window,
15170        cx: &mut Context<Self>,
15171    ) {
15172        if let Some(selections) = self
15173            .change_list
15174            .next_change(1, Direction::Next)
15175            .map(|s| s.to_vec())
15176        {
15177            self.change_selections(Default::default(), window, cx, |s| {
15178                let map = s.display_map();
15179                s.select_display_ranges(selections.iter().map(|a| {
15180                    let point = a.to_display_point(&map);
15181                    point..point
15182                }))
15183            })
15184        }
15185    }
15186
15187    fn go_to_previous_change(
15188        &mut self,
15189        _: &GoToPreviousChange,
15190        window: &mut Window,
15191        cx: &mut Context<Self>,
15192    ) {
15193        if let Some(selections) = self
15194            .change_list
15195            .next_change(1, Direction::Prev)
15196            .map(|s| s.to_vec())
15197        {
15198            self.change_selections(Default::default(), window, cx, |s| {
15199                let map = s.display_map();
15200                s.select_display_ranges(selections.iter().map(|a| {
15201                    let point = a.to_display_point(&map);
15202                    point..point
15203                }))
15204            })
15205        }
15206    }
15207
15208    fn go_to_line<T: 'static>(
15209        &mut self,
15210        position: Anchor,
15211        highlight_color: Option<Hsla>,
15212        window: &mut Window,
15213        cx: &mut Context<Self>,
15214    ) {
15215        let snapshot = self.snapshot(window, cx).display_snapshot;
15216        let position = position.to_point(&snapshot.buffer_snapshot);
15217        let start = snapshot
15218            .buffer_snapshot
15219            .clip_point(Point::new(position.row, 0), Bias::Left);
15220        let end = start + Point::new(1, 0);
15221        let start = snapshot.buffer_snapshot.anchor_before(start);
15222        let end = snapshot.buffer_snapshot.anchor_before(end);
15223
15224        self.highlight_rows::<T>(
15225            start..end,
15226            highlight_color
15227                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15228            Default::default(),
15229            cx,
15230        );
15231
15232        if self.buffer.read(cx).is_singleton() {
15233            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15234        }
15235    }
15236
15237    pub fn go_to_definition(
15238        &mut self,
15239        _: &GoToDefinition,
15240        window: &mut Window,
15241        cx: &mut Context<Self>,
15242    ) -> Task<Result<Navigated>> {
15243        let definition =
15244            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15245        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15246        cx.spawn_in(window, async move |editor, cx| {
15247            if definition.await? == Navigated::Yes {
15248                return Ok(Navigated::Yes);
15249            }
15250            match fallback_strategy {
15251                GoToDefinitionFallback::None => Ok(Navigated::No),
15252                GoToDefinitionFallback::FindAllReferences => {
15253                    match editor.update_in(cx, |editor, window, cx| {
15254                        editor.find_all_references(&FindAllReferences, window, cx)
15255                    })? {
15256                        Some(references) => references.await,
15257                        None => Ok(Navigated::No),
15258                    }
15259                }
15260            }
15261        })
15262    }
15263
15264    pub fn go_to_declaration(
15265        &mut self,
15266        _: &GoToDeclaration,
15267        window: &mut Window,
15268        cx: &mut Context<Self>,
15269    ) -> Task<Result<Navigated>> {
15270        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15271    }
15272
15273    pub fn go_to_declaration_split(
15274        &mut self,
15275        _: &GoToDeclaration,
15276        window: &mut Window,
15277        cx: &mut Context<Self>,
15278    ) -> Task<Result<Navigated>> {
15279        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15280    }
15281
15282    pub fn go_to_implementation(
15283        &mut self,
15284        _: &GoToImplementation,
15285        window: &mut Window,
15286        cx: &mut Context<Self>,
15287    ) -> Task<Result<Navigated>> {
15288        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15289    }
15290
15291    pub fn go_to_implementation_split(
15292        &mut self,
15293        _: &GoToImplementationSplit,
15294        window: &mut Window,
15295        cx: &mut Context<Self>,
15296    ) -> Task<Result<Navigated>> {
15297        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15298    }
15299
15300    pub fn go_to_type_definition(
15301        &mut self,
15302        _: &GoToTypeDefinition,
15303        window: &mut Window,
15304        cx: &mut Context<Self>,
15305    ) -> Task<Result<Navigated>> {
15306        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15307    }
15308
15309    pub fn go_to_definition_split(
15310        &mut self,
15311        _: &GoToDefinitionSplit,
15312        window: &mut Window,
15313        cx: &mut Context<Self>,
15314    ) -> Task<Result<Navigated>> {
15315        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15316    }
15317
15318    pub fn go_to_type_definition_split(
15319        &mut self,
15320        _: &GoToTypeDefinitionSplit,
15321        window: &mut Window,
15322        cx: &mut Context<Self>,
15323    ) -> Task<Result<Navigated>> {
15324        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15325    }
15326
15327    fn go_to_definition_of_kind(
15328        &mut self,
15329        kind: GotoDefinitionKind,
15330        split: bool,
15331        window: &mut Window,
15332        cx: &mut Context<Self>,
15333    ) -> Task<Result<Navigated>> {
15334        let Some(provider) = self.semantics_provider.clone() else {
15335            return Task::ready(Ok(Navigated::No));
15336        };
15337        let head = self.selections.newest::<usize>(cx).head();
15338        let buffer = self.buffer.read(cx);
15339        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15340            text_anchor
15341        } else {
15342            return Task::ready(Ok(Navigated::No));
15343        };
15344
15345        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15346            return Task::ready(Ok(Navigated::No));
15347        };
15348
15349        cx.spawn_in(window, async move |editor, cx| {
15350            let definitions = definitions.await?;
15351            let navigated = editor
15352                .update_in(cx, |editor, window, cx| {
15353                    editor.navigate_to_hover_links(
15354                        Some(kind),
15355                        definitions
15356                            .into_iter()
15357                            .filter(|location| {
15358                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15359                            })
15360                            .map(HoverLink::Text)
15361                            .collect::<Vec<_>>(),
15362                        split,
15363                        window,
15364                        cx,
15365                    )
15366                })?
15367                .await?;
15368            anyhow::Ok(navigated)
15369        })
15370    }
15371
15372    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15373        let selection = self.selections.newest_anchor();
15374        let head = selection.head();
15375        let tail = selection.tail();
15376
15377        let Some((buffer, start_position)) =
15378            self.buffer.read(cx).text_anchor_for_position(head, cx)
15379        else {
15380            return;
15381        };
15382
15383        let end_position = if head != tail {
15384            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15385                return;
15386            };
15387            Some(pos)
15388        } else {
15389            None
15390        };
15391
15392        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15393            let url = if let Some(end_pos) = end_position {
15394                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15395            } else {
15396                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15397            };
15398
15399            if let Some(url) = url {
15400                editor.update(cx, |_, cx| {
15401                    cx.open_url(&url);
15402                })
15403            } else {
15404                Ok(())
15405            }
15406        });
15407
15408        url_finder.detach();
15409    }
15410
15411    pub fn open_selected_filename(
15412        &mut self,
15413        _: &OpenSelectedFilename,
15414        window: &mut Window,
15415        cx: &mut Context<Self>,
15416    ) {
15417        let Some(workspace) = self.workspace() else {
15418            return;
15419        };
15420
15421        let position = self.selections.newest_anchor().head();
15422
15423        let Some((buffer, buffer_position)) =
15424            self.buffer.read(cx).text_anchor_for_position(position, cx)
15425        else {
15426            return;
15427        };
15428
15429        let project = self.project.clone();
15430
15431        cx.spawn_in(window, async move |_, cx| {
15432            let result = find_file(&buffer, project, buffer_position, cx).await;
15433
15434            if let Some((_, path)) = result {
15435                workspace
15436                    .update_in(cx, |workspace, window, cx| {
15437                        workspace.open_resolved_path(path, window, cx)
15438                    })?
15439                    .await?;
15440            }
15441            anyhow::Ok(())
15442        })
15443        .detach();
15444    }
15445
15446    pub(crate) fn navigate_to_hover_links(
15447        &mut self,
15448        kind: Option<GotoDefinitionKind>,
15449        mut definitions: Vec<HoverLink>,
15450        split: bool,
15451        window: &mut Window,
15452        cx: &mut Context<Editor>,
15453    ) -> Task<Result<Navigated>> {
15454        // If there is one definition, just open it directly
15455        if definitions.len() == 1 {
15456            let definition = definitions.pop().unwrap();
15457
15458            enum TargetTaskResult {
15459                Location(Option<Location>),
15460                AlreadyNavigated,
15461            }
15462
15463            let target_task = match definition {
15464                HoverLink::Text(link) => {
15465                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15466                }
15467                HoverLink::InlayHint(lsp_location, server_id) => {
15468                    let computation =
15469                        self.compute_target_location(lsp_location, server_id, window, cx);
15470                    cx.background_spawn(async move {
15471                        let location = computation.await?;
15472                        Ok(TargetTaskResult::Location(location))
15473                    })
15474                }
15475                HoverLink::Url(url) => {
15476                    cx.open_url(&url);
15477                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15478                }
15479                HoverLink::File(path) => {
15480                    if let Some(workspace) = self.workspace() {
15481                        cx.spawn_in(window, async move |_, cx| {
15482                            workspace
15483                                .update_in(cx, |workspace, window, cx| {
15484                                    workspace.open_resolved_path(path, window, cx)
15485                                })?
15486                                .await
15487                                .map(|_| TargetTaskResult::AlreadyNavigated)
15488                        })
15489                    } else {
15490                        Task::ready(Ok(TargetTaskResult::Location(None)))
15491                    }
15492                }
15493            };
15494            cx.spawn_in(window, async move |editor, cx| {
15495                let target = match target_task.await.context("target resolution task")? {
15496                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15497                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15498                    TargetTaskResult::Location(Some(target)) => target,
15499                };
15500
15501                editor.update_in(cx, |editor, window, cx| {
15502                    let Some(workspace) = editor.workspace() else {
15503                        return Navigated::No;
15504                    };
15505                    let pane = workspace.read(cx).active_pane().clone();
15506
15507                    let range = target.range.to_point(target.buffer.read(cx));
15508                    let range = editor.range_for_match(&range);
15509                    let range = collapse_multiline_range(range);
15510
15511                    if !split
15512                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15513                    {
15514                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15515                    } else {
15516                        window.defer(cx, move |window, cx| {
15517                            let target_editor: Entity<Self> =
15518                                workspace.update(cx, |workspace, cx| {
15519                                    let pane = if split {
15520                                        workspace.adjacent_pane(window, cx)
15521                                    } else {
15522                                        workspace.active_pane().clone()
15523                                    };
15524
15525                                    workspace.open_project_item(
15526                                        pane,
15527                                        target.buffer.clone(),
15528                                        true,
15529                                        true,
15530                                        window,
15531                                        cx,
15532                                    )
15533                                });
15534                            target_editor.update(cx, |target_editor, cx| {
15535                                // When selecting a definition in a different buffer, disable the nav history
15536                                // to avoid creating a history entry at the previous cursor location.
15537                                pane.update(cx, |pane, _| pane.disable_history());
15538                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15539                                pane.update(cx, |pane, _| pane.enable_history());
15540                            });
15541                        });
15542                    }
15543                    Navigated::Yes
15544                })
15545            })
15546        } else if !definitions.is_empty() {
15547            cx.spawn_in(window, async move |editor, cx| {
15548                let (title, location_tasks, workspace) = editor
15549                    .update_in(cx, |editor, window, cx| {
15550                        let tab_kind = match kind {
15551                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15552                            _ => "Definitions",
15553                        };
15554                        let title = definitions
15555                            .iter()
15556                            .find_map(|definition| match definition {
15557                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15558                                    let buffer = origin.buffer.read(cx);
15559                                    format!(
15560                                        "{} for {}",
15561                                        tab_kind,
15562                                        buffer
15563                                            .text_for_range(origin.range.clone())
15564                                            .collect::<String>()
15565                                    )
15566                                }),
15567                                HoverLink::InlayHint(_, _) => None,
15568                                HoverLink::Url(_) => None,
15569                                HoverLink::File(_) => None,
15570                            })
15571                            .unwrap_or(tab_kind.to_string());
15572                        let location_tasks = definitions
15573                            .into_iter()
15574                            .map(|definition| match definition {
15575                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15576                                HoverLink::InlayHint(lsp_location, server_id) => editor
15577                                    .compute_target_location(lsp_location, server_id, window, cx),
15578                                HoverLink::Url(_) => Task::ready(Ok(None)),
15579                                HoverLink::File(_) => Task::ready(Ok(None)),
15580                            })
15581                            .collect::<Vec<_>>();
15582                        (title, location_tasks, editor.workspace().clone())
15583                    })
15584                    .context("location tasks preparation")?;
15585
15586                let locations: Vec<Location> = future::join_all(location_tasks)
15587                    .await
15588                    .into_iter()
15589                    .filter_map(|location| location.transpose())
15590                    .collect::<Result<_>>()
15591                    .context("location tasks")?;
15592
15593                if locations.is_empty() {
15594                    return Ok(Navigated::No);
15595                }
15596
15597                let Some(workspace) = workspace else {
15598                    return Ok(Navigated::No);
15599                };
15600
15601                let opened = workspace
15602                    .update_in(cx, |workspace, window, cx| {
15603                        Self::open_locations_in_multibuffer(
15604                            workspace,
15605                            locations,
15606                            title,
15607                            split,
15608                            MultibufferSelectionMode::First,
15609                            window,
15610                            cx,
15611                        )
15612                    })
15613                    .ok();
15614
15615                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15616            })
15617        } else {
15618            Task::ready(Ok(Navigated::No))
15619        }
15620    }
15621
15622    fn compute_target_location(
15623        &self,
15624        lsp_location: lsp::Location,
15625        server_id: LanguageServerId,
15626        window: &mut Window,
15627        cx: &mut Context<Self>,
15628    ) -> Task<anyhow::Result<Option<Location>>> {
15629        let Some(project) = self.project.clone() else {
15630            return Task::ready(Ok(None));
15631        };
15632
15633        cx.spawn_in(window, async move |editor, cx| {
15634            let location_task = editor.update(cx, |_, cx| {
15635                project.update(cx, |project, cx| {
15636                    let language_server_name = project
15637                        .language_server_statuses(cx)
15638                        .find(|(id, _)| server_id == *id)
15639                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15640                    language_server_name.map(|language_server_name| {
15641                        project.open_local_buffer_via_lsp(
15642                            lsp_location.uri.clone(),
15643                            server_id,
15644                            language_server_name,
15645                            cx,
15646                        )
15647                    })
15648                })
15649            })?;
15650            let location = match location_task {
15651                Some(task) => Some({
15652                    let target_buffer_handle = task.await.context("open local buffer")?;
15653                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15654                        let target_start = target_buffer
15655                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15656                        let target_end = target_buffer
15657                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15658                        target_buffer.anchor_after(target_start)
15659                            ..target_buffer.anchor_before(target_end)
15660                    })?;
15661                    Location {
15662                        buffer: target_buffer_handle,
15663                        range,
15664                    }
15665                }),
15666                None => None,
15667            };
15668            Ok(location)
15669        })
15670    }
15671
15672    pub fn find_all_references(
15673        &mut self,
15674        _: &FindAllReferences,
15675        window: &mut Window,
15676        cx: &mut Context<Self>,
15677    ) -> Option<Task<Result<Navigated>>> {
15678        let selection = self.selections.newest::<usize>(cx);
15679        let multi_buffer = self.buffer.read(cx);
15680        let head = selection.head();
15681
15682        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15683        let head_anchor = multi_buffer_snapshot.anchor_at(
15684            head,
15685            if head < selection.tail() {
15686                Bias::Right
15687            } else {
15688                Bias::Left
15689            },
15690        );
15691
15692        match self
15693            .find_all_references_task_sources
15694            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15695        {
15696            Ok(_) => {
15697                log::info!(
15698                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15699                );
15700                return None;
15701            }
15702            Err(i) => {
15703                self.find_all_references_task_sources.insert(i, head_anchor);
15704            }
15705        }
15706
15707        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15708        let workspace = self.workspace()?;
15709        let project = workspace.read(cx).project().clone();
15710        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15711        Some(cx.spawn_in(window, async move |editor, cx| {
15712            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15713                if let Ok(i) = editor
15714                    .find_all_references_task_sources
15715                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15716                {
15717                    editor.find_all_references_task_sources.remove(i);
15718                }
15719            });
15720
15721            let locations = references.await?;
15722            if locations.is_empty() {
15723                return anyhow::Ok(Navigated::No);
15724            }
15725
15726            workspace.update_in(cx, |workspace, window, cx| {
15727                let title = locations
15728                    .first()
15729                    .as_ref()
15730                    .map(|location| {
15731                        let buffer = location.buffer.read(cx);
15732                        format!(
15733                            "References to `{}`",
15734                            buffer
15735                                .text_for_range(location.range.clone())
15736                                .collect::<String>()
15737                        )
15738                    })
15739                    .unwrap();
15740                Self::open_locations_in_multibuffer(
15741                    workspace,
15742                    locations,
15743                    title,
15744                    false,
15745                    MultibufferSelectionMode::First,
15746                    window,
15747                    cx,
15748                );
15749                Navigated::Yes
15750            })
15751        }))
15752    }
15753
15754    /// Opens a multibuffer with the given project locations in it
15755    pub fn open_locations_in_multibuffer(
15756        workspace: &mut Workspace,
15757        mut locations: Vec<Location>,
15758        title: String,
15759        split: bool,
15760        multibuffer_selection_mode: MultibufferSelectionMode,
15761        window: &mut Window,
15762        cx: &mut Context<Workspace>,
15763    ) {
15764        if locations.is_empty() {
15765            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15766            return;
15767        }
15768
15769        // If there are multiple definitions, open them in a multibuffer
15770        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15771        let mut locations = locations.into_iter().peekable();
15772        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15773        let capability = workspace.project().read(cx).capability();
15774
15775        let excerpt_buffer = cx.new(|cx| {
15776            let mut multibuffer = MultiBuffer::new(capability);
15777            while let Some(location) = locations.next() {
15778                let buffer = location.buffer.read(cx);
15779                let mut ranges_for_buffer = Vec::new();
15780                let range = location.range.to_point(buffer);
15781                ranges_for_buffer.push(range.clone());
15782
15783                while let Some(next_location) = locations.peek() {
15784                    if next_location.buffer == location.buffer {
15785                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15786                        locations.next();
15787                    } else {
15788                        break;
15789                    }
15790                }
15791
15792                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15793                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15794                    PathKey::for_buffer(&location.buffer, cx),
15795                    location.buffer.clone(),
15796                    ranges_for_buffer,
15797                    DEFAULT_MULTIBUFFER_CONTEXT,
15798                    cx,
15799                );
15800                ranges.extend(new_ranges)
15801            }
15802
15803            multibuffer.with_title(title)
15804        });
15805
15806        let editor = cx.new(|cx| {
15807            Editor::for_multibuffer(
15808                excerpt_buffer,
15809                Some(workspace.project().clone()),
15810                window,
15811                cx,
15812            )
15813        });
15814        editor.update(cx, |editor, cx| {
15815            match multibuffer_selection_mode {
15816                MultibufferSelectionMode::First => {
15817                    if let Some(first_range) = ranges.first() {
15818                        editor.change_selections(
15819                            SelectionEffects::no_scroll(),
15820                            window,
15821                            cx,
15822                            |selections| {
15823                                selections.clear_disjoint();
15824                                selections
15825                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15826                            },
15827                        );
15828                    }
15829                    editor.highlight_background::<Self>(
15830                        &ranges,
15831                        |theme| theme.colors().editor_highlighted_line_background,
15832                        cx,
15833                    );
15834                }
15835                MultibufferSelectionMode::All => {
15836                    editor.change_selections(
15837                        SelectionEffects::no_scroll(),
15838                        window,
15839                        cx,
15840                        |selections| {
15841                            selections.clear_disjoint();
15842                            selections.select_anchor_ranges(ranges);
15843                        },
15844                    );
15845                }
15846            }
15847            editor.register_buffers_with_language_servers(cx);
15848        });
15849
15850        let item = Box::new(editor);
15851        let item_id = item.item_id();
15852
15853        if split {
15854            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15855        } else {
15856            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15857                let (preview_item_id, preview_item_idx) =
15858                    workspace.active_pane().read_with(cx, |pane, _| {
15859                        (pane.preview_item_id(), pane.preview_item_idx())
15860                    });
15861
15862                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15863
15864                if let Some(preview_item_id) = preview_item_id {
15865                    workspace.active_pane().update(cx, |pane, cx| {
15866                        pane.remove_item(preview_item_id, false, false, window, cx);
15867                    });
15868                }
15869            } else {
15870                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15871            }
15872        }
15873        workspace.active_pane().update(cx, |pane, cx| {
15874            pane.set_preview_item_id(Some(item_id), cx);
15875        });
15876    }
15877
15878    pub fn rename(
15879        &mut self,
15880        _: &Rename,
15881        window: &mut Window,
15882        cx: &mut Context<Self>,
15883    ) -> Option<Task<Result<()>>> {
15884        use language::ToOffset as _;
15885
15886        let provider = self.semantics_provider.clone()?;
15887        let selection = self.selections.newest_anchor().clone();
15888        let (cursor_buffer, cursor_buffer_position) = self
15889            .buffer
15890            .read(cx)
15891            .text_anchor_for_position(selection.head(), cx)?;
15892        let (tail_buffer, cursor_buffer_position_end) = self
15893            .buffer
15894            .read(cx)
15895            .text_anchor_for_position(selection.tail(), cx)?;
15896        if tail_buffer != cursor_buffer {
15897            return None;
15898        }
15899
15900        let snapshot = cursor_buffer.read(cx).snapshot();
15901        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15902        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15903        let prepare_rename = provider
15904            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15905            .unwrap_or_else(|| Task::ready(Ok(None)));
15906        drop(snapshot);
15907
15908        Some(cx.spawn_in(window, async move |this, cx| {
15909            let rename_range = if let Some(range) = prepare_rename.await? {
15910                Some(range)
15911            } else {
15912                this.update(cx, |this, cx| {
15913                    let buffer = this.buffer.read(cx).snapshot(cx);
15914                    let mut buffer_highlights = this
15915                        .document_highlights_for_position(selection.head(), &buffer)
15916                        .filter(|highlight| {
15917                            highlight.start.excerpt_id == selection.head().excerpt_id
15918                                && highlight.end.excerpt_id == selection.head().excerpt_id
15919                        });
15920                    buffer_highlights
15921                        .next()
15922                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15923                })?
15924            };
15925            if let Some(rename_range) = rename_range {
15926                this.update_in(cx, |this, window, cx| {
15927                    let snapshot = cursor_buffer.read(cx).snapshot();
15928                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15929                    let cursor_offset_in_rename_range =
15930                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15931                    let cursor_offset_in_rename_range_end =
15932                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15933
15934                    this.take_rename(false, window, cx);
15935                    let buffer = this.buffer.read(cx).read(cx);
15936                    let cursor_offset = selection.head().to_offset(&buffer);
15937                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15938                    let rename_end = rename_start + rename_buffer_range.len();
15939                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15940                    let mut old_highlight_id = None;
15941                    let old_name: Arc<str> = buffer
15942                        .chunks(rename_start..rename_end, true)
15943                        .map(|chunk| {
15944                            if old_highlight_id.is_none() {
15945                                old_highlight_id = chunk.syntax_highlight_id;
15946                            }
15947                            chunk.text
15948                        })
15949                        .collect::<String>()
15950                        .into();
15951
15952                    drop(buffer);
15953
15954                    // Position the selection in the rename editor so that it matches the current selection.
15955                    this.show_local_selections = false;
15956                    let rename_editor = cx.new(|cx| {
15957                        let mut editor = Editor::single_line(window, cx);
15958                        editor.buffer.update(cx, |buffer, cx| {
15959                            buffer.edit([(0..0, old_name.clone())], None, cx)
15960                        });
15961                        let rename_selection_range = match cursor_offset_in_rename_range
15962                            .cmp(&cursor_offset_in_rename_range_end)
15963                        {
15964                            Ordering::Equal => {
15965                                editor.select_all(&SelectAll, window, cx);
15966                                return editor;
15967                            }
15968                            Ordering::Less => {
15969                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15970                            }
15971                            Ordering::Greater => {
15972                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15973                            }
15974                        };
15975                        if rename_selection_range.end > old_name.len() {
15976                            editor.select_all(&SelectAll, window, cx);
15977                        } else {
15978                            editor.change_selections(Default::default(), window, cx, |s| {
15979                                s.select_ranges([rename_selection_range]);
15980                            });
15981                        }
15982                        editor
15983                    });
15984                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15985                        if e == &EditorEvent::Focused {
15986                            cx.emit(EditorEvent::FocusedIn)
15987                        }
15988                    })
15989                    .detach();
15990
15991                    let write_highlights =
15992                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15993                    let read_highlights =
15994                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15995                    let ranges = write_highlights
15996                        .iter()
15997                        .flat_map(|(_, ranges)| ranges.iter())
15998                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15999                        .cloned()
16000                        .collect();
16001
16002                    this.highlight_text::<Rename>(
16003                        ranges,
16004                        HighlightStyle {
16005                            fade_out: Some(0.6),
16006                            ..Default::default()
16007                        },
16008                        cx,
16009                    );
16010                    let rename_focus_handle = rename_editor.focus_handle(cx);
16011                    window.focus(&rename_focus_handle);
16012                    let block_id = this.insert_blocks(
16013                        [BlockProperties {
16014                            style: BlockStyle::Flex,
16015                            placement: BlockPlacement::Below(range.start),
16016                            height: Some(1),
16017                            render: Arc::new({
16018                                let rename_editor = rename_editor.clone();
16019                                move |cx: &mut BlockContext| {
16020                                    let mut text_style = cx.editor_style.text.clone();
16021                                    if let Some(highlight_style) = old_highlight_id
16022                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16023                                    {
16024                                        text_style = text_style.highlight(highlight_style);
16025                                    }
16026                                    div()
16027                                        .block_mouse_except_scroll()
16028                                        .pl(cx.anchor_x)
16029                                        .child(EditorElement::new(
16030                                            &rename_editor,
16031                                            EditorStyle {
16032                                                background: cx.theme().system().transparent,
16033                                                local_player: cx.editor_style.local_player,
16034                                                text: text_style,
16035                                                scrollbar_width: cx.editor_style.scrollbar_width,
16036                                                syntax: cx.editor_style.syntax.clone(),
16037                                                status: cx.editor_style.status.clone(),
16038                                                inlay_hints_style: HighlightStyle {
16039                                                    font_weight: Some(FontWeight::BOLD),
16040                                                    ..make_inlay_hints_style(cx.app)
16041                                                },
16042                                                inline_completion_styles: make_suggestion_styles(
16043                                                    cx.app,
16044                                                ),
16045                                                ..EditorStyle::default()
16046                                            },
16047                                        ))
16048                                        .into_any_element()
16049                                }
16050                            }),
16051                            priority: 0,
16052                            render_in_minimap: true,
16053                        }],
16054                        Some(Autoscroll::fit()),
16055                        cx,
16056                    )[0];
16057                    this.pending_rename = Some(RenameState {
16058                        range,
16059                        old_name,
16060                        editor: rename_editor,
16061                        block_id,
16062                    });
16063                })?;
16064            }
16065
16066            Ok(())
16067        }))
16068    }
16069
16070    pub fn confirm_rename(
16071        &mut self,
16072        _: &ConfirmRename,
16073        window: &mut Window,
16074        cx: &mut Context<Self>,
16075    ) -> Option<Task<Result<()>>> {
16076        let rename = self.take_rename(false, window, cx)?;
16077        let workspace = self.workspace()?.downgrade();
16078        let (buffer, start) = self
16079            .buffer
16080            .read(cx)
16081            .text_anchor_for_position(rename.range.start, cx)?;
16082        let (end_buffer, _) = self
16083            .buffer
16084            .read(cx)
16085            .text_anchor_for_position(rename.range.end, cx)?;
16086        if buffer != end_buffer {
16087            return None;
16088        }
16089
16090        let old_name = rename.old_name;
16091        let new_name = rename.editor.read(cx).text(cx);
16092
16093        let rename = self.semantics_provider.as_ref()?.perform_rename(
16094            &buffer,
16095            start,
16096            new_name.clone(),
16097            cx,
16098        )?;
16099
16100        Some(cx.spawn_in(window, async move |editor, cx| {
16101            let project_transaction = rename.await?;
16102            Self::open_project_transaction(
16103                &editor,
16104                workspace,
16105                project_transaction,
16106                format!("Rename: {}{}", old_name, new_name),
16107                cx,
16108            )
16109            .await?;
16110
16111            editor.update(cx, |editor, cx| {
16112                editor.refresh_document_highlights(cx);
16113            })?;
16114            Ok(())
16115        }))
16116    }
16117
16118    fn take_rename(
16119        &mut self,
16120        moving_cursor: bool,
16121        window: &mut Window,
16122        cx: &mut Context<Self>,
16123    ) -> Option<RenameState> {
16124        let rename = self.pending_rename.take()?;
16125        if rename.editor.focus_handle(cx).is_focused(window) {
16126            window.focus(&self.focus_handle);
16127        }
16128
16129        self.remove_blocks(
16130            [rename.block_id].into_iter().collect(),
16131            Some(Autoscroll::fit()),
16132            cx,
16133        );
16134        self.clear_highlights::<Rename>(cx);
16135        self.show_local_selections = true;
16136
16137        if moving_cursor {
16138            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16139                editor.selections.newest::<usize>(cx).head()
16140            });
16141
16142            // Update the selection to match the position of the selection inside
16143            // the rename editor.
16144            let snapshot = self.buffer.read(cx).read(cx);
16145            let rename_range = rename.range.to_offset(&snapshot);
16146            let cursor_in_editor = snapshot
16147                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16148                .min(rename_range.end);
16149            drop(snapshot);
16150
16151            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16152                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16153            });
16154        } else {
16155            self.refresh_document_highlights(cx);
16156        }
16157
16158        Some(rename)
16159    }
16160
16161    pub fn pending_rename(&self) -> Option<&RenameState> {
16162        self.pending_rename.as_ref()
16163    }
16164
16165    fn format(
16166        &mut self,
16167        _: &Format,
16168        window: &mut Window,
16169        cx: &mut Context<Self>,
16170    ) -> Option<Task<Result<()>>> {
16171        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16172
16173        let project = match &self.project {
16174            Some(project) => project.clone(),
16175            None => return None,
16176        };
16177
16178        Some(self.perform_format(
16179            project,
16180            FormatTrigger::Manual,
16181            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16182            window,
16183            cx,
16184        ))
16185    }
16186
16187    fn format_selections(
16188        &mut self,
16189        _: &FormatSelections,
16190        window: &mut Window,
16191        cx: &mut Context<Self>,
16192    ) -> Option<Task<Result<()>>> {
16193        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16194
16195        let project = match &self.project {
16196            Some(project) => project.clone(),
16197            None => return None,
16198        };
16199
16200        let ranges = self
16201            .selections
16202            .all_adjusted(cx)
16203            .into_iter()
16204            .map(|selection| selection.range())
16205            .collect_vec();
16206
16207        Some(self.perform_format(
16208            project,
16209            FormatTrigger::Manual,
16210            FormatTarget::Ranges(ranges),
16211            window,
16212            cx,
16213        ))
16214    }
16215
16216    fn perform_format(
16217        &mut self,
16218        project: Entity<Project>,
16219        trigger: FormatTrigger,
16220        target: FormatTarget,
16221        window: &mut Window,
16222        cx: &mut Context<Self>,
16223    ) -> Task<Result<()>> {
16224        let buffer = self.buffer.clone();
16225        let (buffers, target) = match target {
16226            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16227            FormatTarget::Ranges(selection_ranges) => {
16228                let multi_buffer = buffer.read(cx);
16229                let snapshot = multi_buffer.read(cx);
16230                let mut buffers = HashSet::default();
16231                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16232                    BTreeMap::new();
16233                for selection_range in selection_ranges {
16234                    for (buffer, buffer_range, _) in
16235                        snapshot.range_to_buffer_ranges(selection_range)
16236                    {
16237                        let buffer_id = buffer.remote_id();
16238                        let start = buffer.anchor_before(buffer_range.start);
16239                        let end = buffer.anchor_after(buffer_range.end);
16240                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16241                        buffer_id_to_ranges
16242                            .entry(buffer_id)
16243                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16244                            .or_insert_with(|| vec![start..end]);
16245                    }
16246                }
16247                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16248            }
16249        };
16250
16251        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16252        let selections_prev = transaction_id_prev
16253            .and_then(|transaction_id_prev| {
16254                // default to selections as they were after the last edit, if we have them,
16255                // instead of how they are now.
16256                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16257                // will take you back to where you made the last edit, instead of staying where you scrolled
16258                self.selection_history
16259                    .transaction(transaction_id_prev)
16260                    .map(|t| t.0.clone())
16261            })
16262            .unwrap_or_else(|| {
16263                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16264                self.selections.disjoint_anchors()
16265            });
16266
16267        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16268        let format = project.update(cx, |project, cx| {
16269            project.format(buffers, target, true, trigger, cx)
16270        });
16271
16272        cx.spawn_in(window, async move |editor, cx| {
16273            let transaction = futures::select_biased! {
16274                transaction = format.log_err().fuse() => transaction,
16275                () = timeout => {
16276                    log::warn!("timed out waiting for formatting");
16277                    None
16278                }
16279            };
16280
16281            buffer
16282                .update(cx, |buffer, cx| {
16283                    if let Some(transaction) = transaction {
16284                        if !buffer.is_singleton() {
16285                            buffer.push_transaction(&transaction.0, cx);
16286                        }
16287                    }
16288                    cx.notify();
16289                })
16290                .ok();
16291
16292            if let Some(transaction_id_now) =
16293                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16294            {
16295                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16296                if has_new_transaction {
16297                    _ = editor.update(cx, |editor, _| {
16298                        editor
16299                            .selection_history
16300                            .insert_transaction(transaction_id_now, selections_prev);
16301                    });
16302                }
16303            }
16304
16305            Ok(())
16306        })
16307    }
16308
16309    fn organize_imports(
16310        &mut self,
16311        _: &OrganizeImports,
16312        window: &mut Window,
16313        cx: &mut Context<Self>,
16314    ) -> Option<Task<Result<()>>> {
16315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16316        let project = match &self.project {
16317            Some(project) => project.clone(),
16318            None => return None,
16319        };
16320        Some(self.perform_code_action_kind(
16321            project,
16322            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16323            window,
16324            cx,
16325        ))
16326    }
16327
16328    fn perform_code_action_kind(
16329        &mut self,
16330        project: Entity<Project>,
16331        kind: CodeActionKind,
16332        window: &mut Window,
16333        cx: &mut Context<Self>,
16334    ) -> Task<Result<()>> {
16335        let buffer = self.buffer.clone();
16336        let buffers = buffer.read(cx).all_buffers();
16337        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16338        let apply_action = project.update(cx, |project, cx| {
16339            project.apply_code_action_kind(buffers, kind, true, cx)
16340        });
16341        cx.spawn_in(window, async move |_, cx| {
16342            let transaction = futures::select_biased! {
16343                () = timeout => {
16344                    log::warn!("timed out waiting for executing code action");
16345                    None
16346                }
16347                transaction = apply_action.log_err().fuse() => transaction,
16348            };
16349            buffer
16350                .update(cx, |buffer, cx| {
16351                    // check if we need this
16352                    if let Some(transaction) = transaction {
16353                        if !buffer.is_singleton() {
16354                            buffer.push_transaction(&transaction.0, cx);
16355                        }
16356                    }
16357                    cx.notify();
16358                })
16359                .ok();
16360            Ok(())
16361        })
16362    }
16363
16364    pub fn restart_language_server(
16365        &mut self,
16366        _: &RestartLanguageServer,
16367        _: &mut Window,
16368        cx: &mut Context<Self>,
16369    ) {
16370        if let Some(project) = self.project.clone() {
16371            self.buffer.update(cx, |multi_buffer, cx| {
16372                project.update(cx, |project, cx| {
16373                    project.restart_language_servers_for_buffers(
16374                        multi_buffer.all_buffers().into_iter().collect(),
16375                        HashSet::default(),
16376                        cx,
16377                    );
16378                });
16379            })
16380        }
16381    }
16382
16383    pub fn stop_language_server(
16384        &mut self,
16385        _: &StopLanguageServer,
16386        _: &mut Window,
16387        cx: &mut Context<Self>,
16388    ) {
16389        if let Some(project) = self.project.clone() {
16390            self.buffer.update(cx, |multi_buffer, cx| {
16391                project.update(cx, |project, cx| {
16392                    project.stop_language_servers_for_buffers(
16393                        multi_buffer.all_buffers().into_iter().collect(),
16394                        HashSet::default(),
16395                        cx,
16396                    );
16397                    cx.emit(project::Event::RefreshInlayHints);
16398                });
16399            });
16400        }
16401    }
16402
16403    fn cancel_language_server_work(
16404        workspace: &mut Workspace,
16405        _: &actions::CancelLanguageServerWork,
16406        _: &mut Window,
16407        cx: &mut Context<Workspace>,
16408    ) {
16409        let project = workspace.project();
16410        let buffers = workspace
16411            .active_item(cx)
16412            .and_then(|item| item.act_as::<Editor>(cx))
16413            .map_or(HashSet::default(), |editor| {
16414                editor.read(cx).buffer.read(cx).all_buffers()
16415            });
16416        project.update(cx, |project, cx| {
16417            project.cancel_language_server_work_for_buffers(buffers, cx);
16418        });
16419    }
16420
16421    fn show_character_palette(
16422        &mut self,
16423        _: &ShowCharacterPalette,
16424        window: &mut Window,
16425        _: &mut Context<Self>,
16426    ) {
16427        window.show_character_palette();
16428    }
16429
16430    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16431        if !self.diagnostics_enabled() {
16432            return;
16433        }
16434
16435        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16436            let buffer = self.buffer.read(cx).snapshot(cx);
16437            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16438            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16439            let is_valid = buffer
16440                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16441                .any(|entry| {
16442                    entry.diagnostic.is_primary
16443                        && !entry.range.is_empty()
16444                        && entry.range.start == primary_range_start
16445                        && entry.diagnostic.message == active_diagnostics.active_message
16446                });
16447
16448            if !is_valid {
16449                self.dismiss_diagnostics(cx);
16450            }
16451        }
16452    }
16453
16454    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16455        match &self.active_diagnostics {
16456            ActiveDiagnostic::Group(group) => Some(group),
16457            _ => None,
16458        }
16459    }
16460
16461    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16462        if !self.diagnostics_enabled() {
16463            return;
16464        }
16465        self.dismiss_diagnostics(cx);
16466        self.active_diagnostics = ActiveDiagnostic::All;
16467    }
16468
16469    fn activate_diagnostics(
16470        &mut self,
16471        buffer_id: BufferId,
16472        diagnostic: DiagnosticEntry<usize>,
16473        window: &mut Window,
16474        cx: &mut Context<Self>,
16475    ) {
16476        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16477            return;
16478        }
16479        self.dismiss_diagnostics(cx);
16480        let snapshot = self.snapshot(window, cx);
16481        let buffer = self.buffer.read(cx).snapshot(cx);
16482        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16483            return;
16484        };
16485
16486        let diagnostic_group = buffer
16487            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16488            .collect::<Vec<_>>();
16489
16490        let blocks =
16491            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16492
16493        let blocks = self.display_map.update(cx, |display_map, cx| {
16494            display_map.insert_blocks(blocks, cx).into_iter().collect()
16495        });
16496        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16497            active_range: buffer.anchor_before(diagnostic.range.start)
16498                ..buffer.anchor_after(diagnostic.range.end),
16499            active_message: diagnostic.diagnostic.message.clone(),
16500            group_id: diagnostic.diagnostic.group_id,
16501            blocks,
16502        });
16503        cx.notify();
16504    }
16505
16506    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16507        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16508            return;
16509        };
16510
16511        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16512        if let ActiveDiagnostic::Group(group) = prev {
16513            self.display_map.update(cx, |display_map, cx| {
16514                display_map.remove_blocks(group.blocks, cx);
16515            });
16516            cx.notify();
16517        }
16518    }
16519
16520    /// Disable inline diagnostics rendering for this editor.
16521    pub fn disable_inline_diagnostics(&mut self) {
16522        self.inline_diagnostics_enabled = false;
16523        self.inline_diagnostics_update = Task::ready(());
16524        self.inline_diagnostics.clear();
16525    }
16526
16527    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16528        self.diagnostics_enabled = false;
16529        self.dismiss_diagnostics(cx);
16530        self.inline_diagnostics_update = Task::ready(());
16531        self.inline_diagnostics.clear();
16532    }
16533
16534    pub fn diagnostics_enabled(&self) -> bool {
16535        self.diagnostics_enabled && self.mode.is_full()
16536    }
16537
16538    pub fn inline_diagnostics_enabled(&self) -> bool {
16539        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16540    }
16541
16542    pub fn show_inline_diagnostics(&self) -> bool {
16543        self.show_inline_diagnostics
16544    }
16545
16546    pub fn toggle_inline_diagnostics(
16547        &mut self,
16548        _: &ToggleInlineDiagnostics,
16549        window: &mut Window,
16550        cx: &mut Context<Editor>,
16551    ) {
16552        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16553        self.refresh_inline_diagnostics(false, window, cx);
16554    }
16555
16556    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16557        self.diagnostics_max_severity = severity;
16558        self.display_map.update(cx, |display_map, _| {
16559            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16560        });
16561    }
16562
16563    pub fn toggle_diagnostics(
16564        &mut self,
16565        _: &ToggleDiagnostics,
16566        window: &mut Window,
16567        cx: &mut Context<Editor>,
16568    ) {
16569        if !self.diagnostics_enabled() {
16570            return;
16571        }
16572
16573        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16574            EditorSettings::get_global(cx)
16575                .diagnostics_max_severity
16576                .filter(|severity| severity != &DiagnosticSeverity::Off)
16577                .unwrap_or(DiagnosticSeverity::Hint)
16578        } else {
16579            DiagnosticSeverity::Off
16580        };
16581        self.set_max_diagnostics_severity(new_severity, cx);
16582        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16583            self.active_diagnostics = ActiveDiagnostic::None;
16584            self.inline_diagnostics_update = Task::ready(());
16585            self.inline_diagnostics.clear();
16586        } else {
16587            self.refresh_inline_diagnostics(false, window, cx);
16588        }
16589
16590        cx.notify();
16591    }
16592
16593    pub fn toggle_minimap(
16594        &mut self,
16595        _: &ToggleMinimap,
16596        window: &mut Window,
16597        cx: &mut Context<Editor>,
16598    ) {
16599        if self.supports_minimap(cx) {
16600            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16601        }
16602    }
16603
16604    fn refresh_inline_diagnostics(
16605        &mut self,
16606        debounce: bool,
16607        window: &mut Window,
16608        cx: &mut Context<Self>,
16609    ) {
16610        let max_severity = ProjectSettings::get_global(cx)
16611            .diagnostics
16612            .inline
16613            .max_severity
16614            .unwrap_or(self.diagnostics_max_severity);
16615
16616        if !self.inline_diagnostics_enabled()
16617            || !self.show_inline_diagnostics
16618            || max_severity == DiagnosticSeverity::Off
16619        {
16620            self.inline_diagnostics_update = Task::ready(());
16621            self.inline_diagnostics.clear();
16622            return;
16623        }
16624
16625        let debounce_ms = ProjectSettings::get_global(cx)
16626            .diagnostics
16627            .inline
16628            .update_debounce_ms;
16629        let debounce = if debounce && debounce_ms > 0 {
16630            Some(Duration::from_millis(debounce_ms))
16631        } else {
16632            None
16633        };
16634        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16635            if let Some(debounce) = debounce {
16636                cx.background_executor().timer(debounce).await;
16637            }
16638            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16639                editor
16640                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16641                    .ok()
16642            }) else {
16643                return;
16644            };
16645
16646            let new_inline_diagnostics = cx
16647                .background_spawn(async move {
16648                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16649                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16650                        let message = diagnostic_entry
16651                            .diagnostic
16652                            .message
16653                            .split_once('\n')
16654                            .map(|(line, _)| line)
16655                            .map(SharedString::new)
16656                            .unwrap_or_else(|| {
16657                                SharedString::from(diagnostic_entry.diagnostic.message)
16658                            });
16659                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16660                        let (Ok(i) | Err(i)) = inline_diagnostics
16661                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16662                        inline_diagnostics.insert(
16663                            i,
16664                            (
16665                                start_anchor,
16666                                InlineDiagnostic {
16667                                    message,
16668                                    group_id: diagnostic_entry.diagnostic.group_id,
16669                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16670                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16671                                    severity: diagnostic_entry.diagnostic.severity,
16672                                },
16673                            ),
16674                        );
16675                    }
16676                    inline_diagnostics
16677                })
16678                .await;
16679
16680            editor
16681                .update(cx, |editor, cx| {
16682                    editor.inline_diagnostics = new_inline_diagnostics;
16683                    cx.notify();
16684                })
16685                .ok();
16686        });
16687    }
16688
16689    fn pull_diagnostics(
16690        &mut self,
16691        buffer_id: Option<BufferId>,
16692        window: &Window,
16693        cx: &mut Context<Self>,
16694    ) -> Option<()> {
16695        if !self.mode().is_full() {
16696            return None;
16697        }
16698        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16699            .diagnostics
16700            .lsp_pull_diagnostics;
16701        if !pull_diagnostics_settings.enabled {
16702            return None;
16703        }
16704        let project = self.project.as_ref()?.downgrade();
16705        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16706        let mut buffers = self.buffer.read(cx).all_buffers();
16707        if let Some(buffer_id) = buffer_id {
16708            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16709        }
16710
16711        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16712            cx.background_executor().timer(debounce).await;
16713
16714            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16715                buffers
16716                    .into_iter()
16717                    .filter_map(|buffer| {
16718                        project
16719                            .update(cx, |project, cx| {
16720                                project.lsp_store().update(cx, |lsp_store, cx| {
16721                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16722                                })
16723                            })
16724                            .ok()
16725                    })
16726                    .collect::<FuturesUnordered<_>>()
16727            }) else {
16728                return;
16729            };
16730
16731            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16732                match pull_task {
16733                    Ok(()) => {
16734                        if editor
16735                            .update_in(cx, |editor, window, cx| {
16736                                editor.update_diagnostics_state(window, cx);
16737                            })
16738                            .is_err()
16739                        {
16740                            return;
16741                        }
16742                    }
16743                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16744                }
16745            }
16746        });
16747
16748        Some(())
16749    }
16750
16751    pub fn set_selections_from_remote(
16752        &mut self,
16753        selections: Vec<Selection<Anchor>>,
16754        pending_selection: Option<Selection<Anchor>>,
16755        window: &mut Window,
16756        cx: &mut Context<Self>,
16757    ) {
16758        let old_cursor_position = self.selections.newest_anchor().head();
16759        self.selections.change_with(cx, |s| {
16760            s.select_anchors(selections);
16761            if let Some(pending_selection) = pending_selection {
16762                s.set_pending(pending_selection, SelectMode::Character);
16763            } else {
16764                s.clear_pending();
16765            }
16766        });
16767        self.selections_did_change(
16768            false,
16769            &old_cursor_position,
16770            SelectionEffects::default(),
16771            window,
16772            cx,
16773        );
16774    }
16775
16776    pub fn transact(
16777        &mut self,
16778        window: &mut Window,
16779        cx: &mut Context<Self>,
16780        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16781    ) -> Option<TransactionId> {
16782        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16783            this.start_transaction_at(Instant::now(), window, cx);
16784            update(this, window, cx);
16785            this.end_transaction_at(Instant::now(), cx)
16786        })
16787    }
16788
16789    pub fn start_transaction_at(
16790        &mut self,
16791        now: Instant,
16792        window: &mut Window,
16793        cx: &mut Context<Self>,
16794    ) {
16795        self.end_selection(window, cx);
16796        if let Some(tx_id) = self
16797            .buffer
16798            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16799        {
16800            self.selection_history
16801                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16802            cx.emit(EditorEvent::TransactionBegun {
16803                transaction_id: tx_id,
16804            })
16805        }
16806    }
16807
16808    pub fn end_transaction_at(
16809        &mut self,
16810        now: Instant,
16811        cx: &mut Context<Self>,
16812    ) -> Option<TransactionId> {
16813        if let Some(transaction_id) = self
16814            .buffer
16815            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16816        {
16817            if let Some((_, end_selections)) =
16818                self.selection_history.transaction_mut(transaction_id)
16819            {
16820                *end_selections = Some(self.selections.disjoint_anchors());
16821            } else {
16822                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16823            }
16824
16825            cx.emit(EditorEvent::Edited { transaction_id });
16826            Some(transaction_id)
16827        } else {
16828            None
16829        }
16830    }
16831
16832    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16833        if self.selection_mark_mode {
16834            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16835                s.move_with(|_, sel| {
16836                    sel.collapse_to(sel.head(), SelectionGoal::None);
16837                });
16838            })
16839        }
16840        self.selection_mark_mode = true;
16841        cx.notify();
16842    }
16843
16844    pub fn swap_selection_ends(
16845        &mut self,
16846        _: &actions::SwapSelectionEnds,
16847        window: &mut Window,
16848        cx: &mut Context<Self>,
16849    ) {
16850        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16851            s.move_with(|_, sel| {
16852                if sel.start != sel.end {
16853                    sel.reversed = !sel.reversed
16854                }
16855            });
16856        });
16857        self.request_autoscroll(Autoscroll::newest(), cx);
16858        cx.notify();
16859    }
16860
16861    pub fn toggle_fold(
16862        &mut self,
16863        _: &actions::ToggleFold,
16864        window: &mut Window,
16865        cx: &mut Context<Self>,
16866    ) {
16867        if self.is_singleton(cx) {
16868            let selection = self.selections.newest::<Point>(cx);
16869
16870            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16871            let range = if selection.is_empty() {
16872                let point = selection.head().to_display_point(&display_map);
16873                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16874                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16875                    .to_point(&display_map);
16876                start..end
16877            } else {
16878                selection.range()
16879            };
16880            if display_map.folds_in_range(range).next().is_some() {
16881                self.unfold_lines(&Default::default(), window, cx)
16882            } else {
16883                self.fold(&Default::default(), window, cx)
16884            }
16885        } else {
16886            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16887            let buffer_ids: HashSet<_> = self
16888                .selections
16889                .disjoint_anchor_ranges()
16890                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16891                .collect();
16892
16893            let should_unfold = buffer_ids
16894                .iter()
16895                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16896
16897            for buffer_id in buffer_ids {
16898                if should_unfold {
16899                    self.unfold_buffer(buffer_id, cx);
16900                } else {
16901                    self.fold_buffer(buffer_id, cx);
16902                }
16903            }
16904        }
16905    }
16906
16907    pub fn toggle_fold_recursive(
16908        &mut self,
16909        _: &actions::ToggleFoldRecursive,
16910        window: &mut Window,
16911        cx: &mut Context<Self>,
16912    ) {
16913        let selection = self.selections.newest::<Point>(cx);
16914
16915        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16916        let range = if selection.is_empty() {
16917            let point = selection.head().to_display_point(&display_map);
16918            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16919            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16920                .to_point(&display_map);
16921            start..end
16922        } else {
16923            selection.range()
16924        };
16925        if display_map.folds_in_range(range).next().is_some() {
16926            self.unfold_recursive(&Default::default(), window, cx)
16927        } else {
16928            self.fold_recursive(&Default::default(), window, cx)
16929        }
16930    }
16931
16932    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16933        if self.is_singleton(cx) {
16934            let mut to_fold = Vec::new();
16935            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16936            let selections = self.selections.all_adjusted(cx);
16937
16938            for selection in selections {
16939                let range = selection.range().sorted();
16940                let buffer_start_row = range.start.row;
16941
16942                if range.start.row != range.end.row {
16943                    let mut found = false;
16944                    let mut row = range.start.row;
16945                    while row <= range.end.row {
16946                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16947                        {
16948                            found = true;
16949                            row = crease.range().end.row + 1;
16950                            to_fold.push(crease);
16951                        } else {
16952                            row += 1
16953                        }
16954                    }
16955                    if found {
16956                        continue;
16957                    }
16958                }
16959
16960                for row in (0..=range.start.row).rev() {
16961                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16962                        if crease.range().end.row >= buffer_start_row {
16963                            to_fold.push(crease);
16964                            if row <= range.start.row {
16965                                break;
16966                            }
16967                        }
16968                    }
16969                }
16970            }
16971
16972            self.fold_creases(to_fold, true, window, cx);
16973        } else {
16974            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16975            let buffer_ids = self
16976                .selections
16977                .disjoint_anchor_ranges()
16978                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16979                .collect::<HashSet<_>>();
16980            for buffer_id in buffer_ids {
16981                self.fold_buffer(buffer_id, cx);
16982            }
16983        }
16984    }
16985
16986    fn fold_at_level(
16987        &mut self,
16988        fold_at: &FoldAtLevel,
16989        window: &mut Window,
16990        cx: &mut Context<Self>,
16991    ) {
16992        if !self.buffer.read(cx).is_singleton() {
16993            return;
16994        }
16995
16996        let fold_at_level = fold_at.0;
16997        let snapshot = self.buffer.read(cx).snapshot(cx);
16998        let mut to_fold = Vec::new();
16999        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17000
17001        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17002            while start_row < end_row {
17003                match self
17004                    .snapshot(window, cx)
17005                    .crease_for_buffer_row(MultiBufferRow(start_row))
17006                {
17007                    Some(crease) => {
17008                        let nested_start_row = crease.range().start.row + 1;
17009                        let nested_end_row = crease.range().end.row;
17010
17011                        if current_level < fold_at_level {
17012                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17013                        } else if current_level == fold_at_level {
17014                            to_fold.push(crease);
17015                        }
17016
17017                        start_row = nested_end_row + 1;
17018                    }
17019                    None => start_row += 1,
17020                }
17021            }
17022        }
17023
17024        self.fold_creases(to_fold, true, window, cx);
17025    }
17026
17027    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17028        if self.buffer.read(cx).is_singleton() {
17029            let mut fold_ranges = Vec::new();
17030            let snapshot = self.buffer.read(cx).snapshot(cx);
17031
17032            for row in 0..snapshot.max_row().0 {
17033                if let Some(foldable_range) = self
17034                    .snapshot(window, cx)
17035                    .crease_for_buffer_row(MultiBufferRow(row))
17036                {
17037                    fold_ranges.push(foldable_range);
17038                }
17039            }
17040
17041            self.fold_creases(fold_ranges, true, window, cx);
17042        } else {
17043            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17044                editor
17045                    .update_in(cx, |editor, _, cx| {
17046                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17047                            editor.fold_buffer(buffer_id, cx);
17048                        }
17049                    })
17050                    .ok();
17051            });
17052        }
17053    }
17054
17055    pub fn fold_function_bodies(
17056        &mut self,
17057        _: &actions::FoldFunctionBodies,
17058        window: &mut Window,
17059        cx: &mut Context<Self>,
17060    ) {
17061        let snapshot = self.buffer.read(cx).snapshot(cx);
17062
17063        let ranges = snapshot
17064            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17065            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17066            .collect::<Vec<_>>();
17067
17068        let creases = ranges
17069            .into_iter()
17070            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17071            .collect();
17072
17073        self.fold_creases(creases, true, window, cx);
17074    }
17075
17076    pub fn fold_recursive(
17077        &mut self,
17078        _: &actions::FoldRecursive,
17079        window: &mut Window,
17080        cx: &mut Context<Self>,
17081    ) {
17082        let mut to_fold = Vec::new();
17083        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17084        let selections = self.selections.all_adjusted(cx);
17085
17086        for selection in selections {
17087            let range = selection.range().sorted();
17088            let buffer_start_row = range.start.row;
17089
17090            if range.start.row != range.end.row {
17091                let mut found = false;
17092                for row in range.start.row..=range.end.row {
17093                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17094                        found = true;
17095                        to_fold.push(crease);
17096                    }
17097                }
17098                if found {
17099                    continue;
17100                }
17101            }
17102
17103            for row in (0..=range.start.row).rev() {
17104                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17105                    if crease.range().end.row >= buffer_start_row {
17106                        to_fold.push(crease);
17107                    } else {
17108                        break;
17109                    }
17110                }
17111            }
17112        }
17113
17114        self.fold_creases(to_fold, true, window, cx);
17115    }
17116
17117    pub fn fold_at(
17118        &mut self,
17119        buffer_row: MultiBufferRow,
17120        window: &mut Window,
17121        cx: &mut Context<Self>,
17122    ) {
17123        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17124
17125        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17126            let autoscroll = self
17127                .selections
17128                .all::<Point>(cx)
17129                .iter()
17130                .any(|selection| crease.range().overlaps(&selection.range()));
17131
17132            self.fold_creases(vec![crease], autoscroll, window, cx);
17133        }
17134    }
17135
17136    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17137        if self.is_singleton(cx) {
17138            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17139            let buffer = &display_map.buffer_snapshot;
17140            let selections = self.selections.all::<Point>(cx);
17141            let ranges = selections
17142                .iter()
17143                .map(|s| {
17144                    let range = s.display_range(&display_map).sorted();
17145                    let mut start = range.start.to_point(&display_map);
17146                    let mut end = range.end.to_point(&display_map);
17147                    start.column = 0;
17148                    end.column = buffer.line_len(MultiBufferRow(end.row));
17149                    start..end
17150                })
17151                .collect::<Vec<_>>();
17152
17153            self.unfold_ranges(&ranges, true, true, cx);
17154        } else {
17155            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17156            let buffer_ids = self
17157                .selections
17158                .disjoint_anchor_ranges()
17159                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17160                .collect::<HashSet<_>>();
17161            for buffer_id in buffer_ids {
17162                self.unfold_buffer(buffer_id, cx);
17163            }
17164        }
17165    }
17166
17167    pub fn unfold_recursive(
17168        &mut self,
17169        _: &UnfoldRecursive,
17170        _window: &mut Window,
17171        cx: &mut Context<Self>,
17172    ) {
17173        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17174        let selections = self.selections.all::<Point>(cx);
17175        let ranges = selections
17176            .iter()
17177            .map(|s| {
17178                let mut range = s.display_range(&display_map).sorted();
17179                *range.start.column_mut() = 0;
17180                *range.end.column_mut() = display_map.line_len(range.end.row());
17181                let start = range.start.to_point(&display_map);
17182                let end = range.end.to_point(&display_map);
17183                start..end
17184            })
17185            .collect::<Vec<_>>();
17186
17187        self.unfold_ranges(&ranges, true, true, cx);
17188    }
17189
17190    pub fn unfold_at(
17191        &mut self,
17192        buffer_row: MultiBufferRow,
17193        _window: &mut Window,
17194        cx: &mut Context<Self>,
17195    ) {
17196        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17197
17198        let intersection_range = Point::new(buffer_row.0, 0)
17199            ..Point::new(
17200                buffer_row.0,
17201                display_map.buffer_snapshot.line_len(buffer_row),
17202            );
17203
17204        let autoscroll = self
17205            .selections
17206            .all::<Point>(cx)
17207            .iter()
17208            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17209
17210        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17211    }
17212
17213    pub fn unfold_all(
17214        &mut self,
17215        _: &actions::UnfoldAll,
17216        _window: &mut Window,
17217        cx: &mut Context<Self>,
17218    ) {
17219        if self.buffer.read(cx).is_singleton() {
17220            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17221            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17222        } else {
17223            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17224                editor
17225                    .update(cx, |editor, cx| {
17226                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17227                            editor.unfold_buffer(buffer_id, cx);
17228                        }
17229                    })
17230                    .ok();
17231            });
17232        }
17233    }
17234
17235    pub fn fold_selected_ranges(
17236        &mut self,
17237        _: &FoldSelectedRanges,
17238        window: &mut Window,
17239        cx: &mut Context<Self>,
17240    ) {
17241        let selections = self.selections.all_adjusted(cx);
17242        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17243        let ranges = selections
17244            .into_iter()
17245            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17246            .collect::<Vec<_>>();
17247        self.fold_creases(ranges, true, window, cx);
17248    }
17249
17250    pub fn fold_ranges<T: ToOffset + Clone>(
17251        &mut self,
17252        ranges: Vec<Range<T>>,
17253        auto_scroll: bool,
17254        window: &mut Window,
17255        cx: &mut Context<Self>,
17256    ) {
17257        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17258        let ranges = ranges
17259            .into_iter()
17260            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17261            .collect::<Vec<_>>();
17262        self.fold_creases(ranges, auto_scroll, window, cx);
17263    }
17264
17265    pub fn fold_creases<T: ToOffset + Clone>(
17266        &mut self,
17267        creases: Vec<Crease<T>>,
17268        auto_scroll: bool,
17269        _window: &mut Window,
17270        cx: &mut Context<Self>,
17271    ) {
17272        if creases.is_empty() {
17273            return;
17274        }
17275
17276        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17277
17278        if auto_scroll {
17279            self.request_autoscroll(Autoscroll::fit(), cx);
17280        }
17281
17282        cx.notify();
17283
17284        self.scrollbar_marker_state.dirty = true;
17285        self.folds_did_change(cx);
17286    }
17287
17288    /// Removes any folds whose ranges intersect any of the given ranges.
17289    pub fn unfold_ranges<T: ToOffset + Clone>(
17290        &mut self,
17291        ranges: &[Range<T>],
17292        inclusive: bool,
17293        auto_scroll: bool,
17294        cx: &mut Context<Self>,
17295    ) {
17296        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17297            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17298        });
17299        self.folds_did_change(cx);
17300    }
17301
17302    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17303        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17304            return;
17305        }
17306        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17307        self.display_map.update(cx, |display_map, cx| {
17308            display_map.fold_buffers([buffer_id], cx)
17309        });
17310        cx.emit(EditorEvent::BufferFoldToggled {
17311            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17312            folded: true,
17313        });
17314        cx.notify();
17315    }
17316
17317    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17318        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17319            return;
17320        }
17321        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17322        self.display_map.update(cx, |display_map, cx| {
17323            display_map.unfold_buffers([buffer_id], cx);
17324        });
17325        cx.emit(EditorEvent::BufferFoldToggled {
17326            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17327            folded: false,
17328        });
17329        cx.notify();
17330    }
17331
17332    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17333        self.display_map.read(cx).is_buffer_folded(buffer)
17334    }
17335
17336    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17337        self.display_map.read(cx).folded_buffers()
17338    }
17339
17340    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17341        self.display_map.update(cx, |display_map, cx| {
17342            display_map.disable_header_for_buffer(buffer_id, cx);
17343        });
17344        cx.notify();
17345    }
17346
17347    /// Removes any folds with the given ranges.
17348    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17349        &mut self,
17350        ranges: &[Range<T>],
17351        type_id: TypeId,
17352        auto_scroll: bool,
17353        cx: &mut Context<Self>,
17354    ) {
17355        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17356            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17357        });
17358        self.folds_did_change(cx);
17359    }
17360
17361    fn remove_folds_with<T: ToOffset + Clone>(
17362        &mut self,
17363        ranges: &[Range<T>],
17364        auto_scroll: bool,
17365        cx: &mut Context<Self>,
17366        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17367    ) {
17368        if ranges.is_empty() {
17369            return;
17370        }
17371
17372        let mut buffers_affected = HashSet::default();
17373        let multi_buffer = self.buffer().read(cx);
17374        for range in ranges {
17375            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17376                buffers_affected.insert(buffer.read(cx).remote_id());
17377            };
17378        }
17379
17380        self.display_map.update(cx, update);
17381
17382        if auto_scroll {
17383            self.request_autoscroll(Autoscroll::fit(), cx);
17384        }
17385
17386        cx.notify();
17387        self.scrollbar_marker_state.dirty = true;
17388        self.active_indent_guides_state.dirty = true;
17389    }
17390
17391    pub fn update_renderer_widths(
17392        &mut self,
17393        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17394        cx: &mut Context<Self>,
17395    ) -> bool {
17396        self.display_map
17397            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17398    }
17399
17400    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17401        self.display_map.read(cx).fold_placeholder.clone()
17402    }
17403
17404    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17405        self.buffer.update(cx, |buffer, cx| {
17406            buffer.set_all_diff_hunks_expanded(cx);
17407        });
17408    }
17409
17410    pub fn expand_all_diff_hunks(
17411        &mut self,
17412        _: &ExpandAllDiffHunks,
17413        _window: &mut Window,
17414        cx: &mut Context<Self>,
17415    ) {
17416        self.buffer.update(cx, |buffer, cx| {
17417            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17418        });
17419    }
17420
17421    pub fn toggle_selected_diff_hunks(
17422        &mut self,
17423        _: &ToggleSelectedDiffHunks,
17424        _window: &mut Window,
17425        cx: &mut Context<Self>,
17426    ) {
17427        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17428        self.toggle_diff_hunks_in_ranges(ranges, cx);
17429    }
17430
17431    pub fn diff_hunks_in_ranges<'a>(
17432        &'a self,
17433        ranges: &'a [Range<Anchor>],
17434        buffer: &'a MultiBufferSnapshot,
17435    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17436        ranges.iter().flat_map(move |range| {
17437            let end_excerpt_id = range.end.excerpt_id;
17438            let range = range.to_point(buffer);
17439            let mut peek_end = range.end;
17440            if range.end.row < buffer.max_row().0 {
17441                peek_end = Point::new(range.end.row + 1, 0);
17442            }
17443            buffer
17444                .diff_hunks_in_range(range.start..peek_end)
17445                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17446        })
17447    }
17448
17449    pub fn has_stageable_diff_hunks_in_ranges(
17450        &self,
17451        ranges: &[Range<Anchor>],
17452        snapshot: &MultiBufferSnapshot,
17453    ) -> bool {
17454        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17455        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17456    }
17457
17458    pub fn toggle_staged_selected_diff_hunks(
17459        &mut self,
17460        _: &::git::ToggleStaged,
17461        _: &mut Window,
17462        cx: &mut Context<Self>,
17463    ) {
17464        let snapshot = self.buffer.read(cx).snapshot(cx);
17465        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17466        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17467        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17468    }
17469
17470    pub fn set_render_diff_hunk_controls(
17471        &mut self,
17472        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17473        cx: &mut Context<Self>,
17474    ) {
17475        self.render_diff_hunk_controls = render_diff_hunk_controls;
17476        cx.notify();
17477    }
17478
17479    pub fn stage_and_next(
17480        &mut self,
17481        _: &::git::StageAndNext,
17482        window: &mut Window,
17483        cx: &mut Context<Self>,
17484    ) {
17485        self.do_stage_or_unstage_and_next(true, window, cx);
17486    }
17487
17488    pub fn unstage_and_next(
17489        &mut self,
17490        _: &::git::UnstageAndNext,
17491        window: &mut Window,
17492        cx: &mut Context<Self>,
17493    ) {
17494        self.do_stage_or_unstage_and_next(false, window, cx);
17495    }
17496
17497    pub fn stage_or_unstage_diff_hunks(
17498        &mut self,
17499        stage: bool,
17500        ranges: Vec<Range<Anchor>>,
17501        cx: &mut Context<Self>,
17502    ) {
17503        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17504        cx.spawn(async move |this, cx| {
17505            task.await?;
17506            this.update(cx, |this, cx| {
17507                let snapshot = this.buffer.read(cx).snapshot(cx);
17508                let chunk_by = this
17509                    .diff_hunks_in_ranges(&ranges, &snapshot)
17510                    .chunk_by(|hunk| hunk.buffer_id);
17511                for (buffer_id, hunks) in &chunk_by {
17512                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17513                }
17514            })
17515        })
17516        .detach_and_log_err(cx);
17517    }
17518
17519    fn save_buffers_for_ranges_if_needed(
17520        &mut self,
17521        ranges: &[Range<Anchor>],
17522        cx: &mut Context<Editor>,
17523    ) -> Task<Result<()>> {
17524        let multibuffer = self.buffer.read(cx);
17525        let snapshot = multibuffer.read(cx);
17526        let buffer_ids: HashSet<_> = ranges
17527            .iter()
17528            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17529            .collect();
17530        drop(snapshot);
17531
17532        let mut buffers = HashSet::default();
17533        for buffer_id in buffer_ids {
17534            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17535                let buffer = buffer_entity.read(cx);
17536                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17537                {
17538                    buffers.insert(buffer_entity);
17539                }
17540            }
17541        }
17542
17543        if let Some(project) = &self.project {
17544            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17545        } else {
17546            Task::ready(Ok(()))
17547        }
17548    }
17549
17550    fn do_stage_or_unstage_and_next(
17551        &mut self,
17552        stage: bool,
17553        window: &mut Window,
17554        cx: &mut Context<Self>,
17555    ) {
17556        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17557
17558        if ranges.iter().any(|range| range.start != range.end) {
17559            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17560            return;
17561        }
17562
17563        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17564        let snapshot = self.snapshot(window, cx);
17565        let position = self.selections.newest::<Point>(cx).head();
17566        let mut row = snapshot
17567            .buffer_snapshot
17568            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17569            .find(|hunk| hunk.row_range.start.0 > position.row)
17570            .map(|hunk| hunk.row_range.start);
17571
17572        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17573        // Outside of the project diff editor, wrap around to the beginning.
17574        if !all_diff_hunks_expanded {
17575            row = row.or_else(|| {
17576                snapshot
17577                    .buffer_snapshot
17578                    .diff_hunks_in_range(Point::zero()..position)
17579                    .find(|hunk| hunk.row_range.end.0 < position.row)
17580                    .map(|hunk| hunk.row_range.start)
17581            });
17582        }
17583
17584        if let Some(row) = row {
17585            let destination = Point::new(row.0, 0);
17586            let autoscroll = Autoscroll::center();
17587
17588            self.unfold_ranges(&[destination..destination], false, false, cx);
17589            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17590                s.select_ranges([destination..destination]);
17591            });
17592        }
17593    }
17594
17595    fn do_stage_or_unstage(
17596        &self,
17597        stage: bool,
17598        buffer_id: BufferId,
17599        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17600        cx: &mut App,
17601    ) -> Option<()> {
17602        let project = self.project.as_ref()?;
17603        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17604        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17605        let buffer_snapshot = buffer.read(cx).snapshot();
17606        let file_exists = buffer_snapshot
17607            .file()
17608            .is_some_and(|file| file.disk_state().exists());
17609        diff.update(cx, |diff, cx| {
17610            diff.stage_or_unstage_hunks(
17611                stage,
17612                &hunks
17613                    .map(|hunk| buffer_diff::DiffHunk {
17614                        buffer_range: hunk.buffer_range,
17615                        diff_base_byte_range: hunk.diff_base_byte_range,
17616                        secondary_status: hunk.secondary_status,
17617                        range: Point::zero()..Point::zero(), // unused
17618                    })
17619                    .collect::<Vec<_>>(),
17620                &buffer_snapshot,
17621                file_exists,
17622                cx,
17623            )
17624        });
17625        None
17626    }
17627
17628    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17629        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17630        self.buffer
17631            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17632    }
17633
17634    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17635        self.buffer.update(cx, |buffer, cx| {
17636            let ranges = vec![Anchor::min()..Anchor::max()];
17637            if !buffer.all_diff_hunks_expanded()
17638                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17639            {
17640                buffer.collapse_diff_hunks(ranges, cx);
17641                true
17642            } else {
17643                false
17644            }
17645        })
17646    }
17647
17648    fn toggle_diff_hunks_in_ranges(
17649        &mut self,
17650        ranges: Vec<Range<Anchor>>,
17651        cx: &mut Context<Editor>,
17652    ) {
17653        self.buffer.update(cx, |buffer, cx| {
17654            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17655            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17656        })
17657    }
17658
17659    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17660        self.buffer.update(cx, |buffer, cx| {
17661            let snapshot = buffer.snapshot(cx);
17662            let excerpt_id = range.end.excerpt_id;
17663            let point_range = range.to_point(&snapshot);
17664            let expand = !buffer.single_hunk_is_expanded(range, cx);
17665            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17666        })
17667    }
17668
17669    pub(crate) fn apply_all_diff_hunks(
17670        &mut self,
17671        _: &ApplyAllDiffHunks,
17672        window: &mut Window,
17673        cx: &mut Context<Self>,
17674    ) {
17675        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17676
17677        let buffers = self.buffer.read(cx).all_buffers();
17678        for branch_buffer in buffers {
17679            branch_buffer.update(cx, |branch_buffer, cx| {
17680                branch_buffer.merge_into_base(Vec::new(), cx);
17681            });
17682        }
17683
17684        if let Some(project) = self.project.clone() {
17685            self.save(
17686                SaveOptions {
17687                    format: true,
17688                    autosave: false,
17689                },
17690                project,
17691                window,
17692                cx,
17693            )
17694            .detach_and_log_err(cx);
17695        }
17696    }
17697
17698    pub(crate) fn apply_selected_diff_hunks(
17699        &mut self,
17700        _: &ApplyDiffHunk,
17701        window: &mut Window,
17702        cx: &mut Context<Self>,
17703    ) {
17704        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17705        let snapshot = self.snapshot(window, cx);
17706        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17707        let mut ranges_by_buffer = HashMap::default();
17708        self.transact(window, cx, |editor, _window, cx| {
17709            for hunk in hunks {
17710                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17711                    ranges_by_buffer
17712                        .entry(buffer.clone())
17713                        .or_insert_with(Vec::new)
17714                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17715                }
17716            }
17717
17718            for (buffer, ranges) in ranges_by_buffer {
17719                buffer.update(cx, |buffer, cx| {
17720                    buffer.merge_into_base(ranges, cx);
17721                });
17722            }
17723        });
17724
17725        if let Some(project) = self.project.clone() {
17726            self.save(
17727                SaveOptions {
17728                    format: true,
17729                    autosave: false,
17730                },
17731                project,
17732                window,
17733                cx,
17734            )
17735            .detach_and_log_err(cx);
17736        }
17737    }
17738
17739    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17740        if hovered != self.gutter_hovered {
17741            self.gutter_hovered = hovered;
17742            cx.notify();
17743        }
17744    }
17745
17746    pub fn insert_blocks(
17747        &mut self,
17748        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17749        autoscroll: Option<Autoscroll>,
17750        cx: &mut Context<Self>,
17751    ) -> Vec<CustomBlockId> {
17752        let blocks = self
17753            .display_map
17754            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17755        if let Some(autoscroll) = autoscroll {
17756            self.request_autoscroll(autoscroll, cx);
17757        }
17758        cx.notify();
17759        blocks
17760    }
17761
17762    pub fn resize_blocks(
17763        &mut self,
17764        heights: HashMap<CustomBlockId, u32>,
17765        autoscroll: Option<Autoscroll>,
17766        cx: &mut Context<Self>,
17767    ) {
17768        self.display_map
17769            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17770        if let Some(autoscroll) = autoscroll {
17771            self.request_autoscroll(autoscroll, cx);
17772        }
17773        cx.notify();
17774    }
17775
17776    pub fn replace_blocks(
17777        &mut self,
17778        renderers: HashMap<CustomBlockId, RenderBlock>,
17779        autoscroll: Option<Autoscroll>,
17780        cx: &mut Context<Self>,
17781    ) {
17782        self.display_map
17783            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17784        if let Some(autoscroll) = autoscroll {
17785            self.request_autoscroll(autoscroll, cx);
17786        }
17787        cx.notify();
17788    }
17789
17790    pub fn remove_blocks(
17791        &mut self,
17792        block_ids: HashSet<CustomBlockId>,
17793        autoscroll: Option<Autoscroll>,
17794        cx: &mut Context<Self>,
17795    ) {
17796        self.display_map.update(cx, |display_map, cx| {
17797            display_map.remove_blocks(block_ids, cx)
17798        });
17799        if let Some(autoscroll) = autoscroll {
17800            self.request_autoscroll(autoscroll, cx);
17801        }
17802        cx.notify();
17803    }
17804
17805    pub fn row_for_block(
17806        &self,
17807        block_id: CustomBlockId,
17808        cx: &mut Context<Self>,
17809    ) -> Option<DisplayRow> {
17810        self.display_map
17811            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17812    }
17813
17814    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17815        self.focused_block = Some(focused_block);
17816    }
17817
17818    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17819        self.focused_block.take()
17820    }
17821
17822    pub fn insert_creases(
17823        &mut self,
17824        creases: impl IntoIterator<Item = Crease<Anchor>>,
17825        cx: &mut Context<Self>,
17826    ) -> Vec<CreaseId> {
17827        self.display_map
17828            .update(cx, |map, cx| map.insert_creases(creases, cx))
17829    }
17830
17831    pub fn remove_creases(
17832        &mut self,
17833        ids: impl IntoIterator<Item = CreaseId>,
17834        cx: &mut Context<Self>,
17835    ) -> Vec<(CreaseId, Range<Anchor>)> {
17836        self.display_map
17837            .update(cx, |map, cx| map.remove_creases(ids, cx))
17838    }
17839
17840    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17841        self.display_map
17842            .update(cx, |map, cx| map.snapshot(cx))
17843            .longest_row()
17844    }
17845
17846    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17847        self.display_map
17848            .update(cx, |map, cx| map.snapshot(cx))
17849            .max_point()
17850    }
17851
17852    pub fn text(&self, cx: &App) -> String {
17853        self.buffer.read(cx).read(cx).text()
17854    }
17855
17856    pub fn is_empty(&self, cx: &App) -> bool {
17857        self.buffer.read(cx).read(cx).is_empty()
17858    }
17859
17860    pub fn text_option(&self, cx: &App) -> Option<String> {
17861        let text = self.text(cx);
17862        let text = text.trim();
17863
17864        if text.is_empty() {
17865            return None;
17866        }
17867
17868        Some(text.to_string())
17869    }
17870
17871    pub fn set_text(
17872        &mut self,
17873        text: impl Into<Arc<str>>,
17874        window: &mut Window,
17875        cx: &mut Context<Self>,
17876    ) {
17877        self.transact(window, cx, |this, _, cx| {
17878            this.buffer
17879                .read(cx)
17880                .as_singleton()
17881                .expect("you can only call set_text on editors for singleton buffers")
17882                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17883        });
17884    }
17885
17886    pub fn display_text(&self, cx: &mut App) -> String {
17887        self.display_map
17888            .update(cx, |map, cx| map.snapshot(cx))
17889            .text()
17890    }
17891
17892    fn create_minimap(
17893        &self,
17894        minimap_settings: MinimapSettings,
17895        window: &mut Window,
17896        cx: &mut Context<Self>,
17897    ) -> Option<Entity<Self>> {
17898        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17899            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17900    }
17901
17902    fn initialize_new_minimap(
17903        &self,
17904        minimap_settings: MinimapSettings,
17905        window: &mut Window,
17906        cx: &mut Context<Self>,
17907    ) -> Entity<Self> {
17908        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17909
17910        let mut minimap = Editor::new_internal(
17911            EditorMode::Minimap {
17912                parent: cx.weak_entity(),
17913            },
17914            self.buffer.clone(),
17915            self.project.clone(),
17916            Some(self.display_map.clone()),
17917            window,
17918            cx,
17919        );
17920        minimap.scroll_manager.clone_state(&self.scroll_manager);
17921        minimap.set_text_style_refinement(TextStyleRefinement {
17922            font_size: Some(MINIMAP_FONT_SIZE),
17923            font_weight: Some(MINIMAP_FONT_WEIGHT),
17924            ..Default::default()
17925        });
17926        minimap.update_minimap_configuration(minimap_settings, cx);
17927        cx.new(|_| minimap)
17928    }
17929
17930    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17931        let current_line_highlight = minimap_settings
17932            .current_line_highlight
17933            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17934        self.set_current_line_highlight(Some(current_line_highlight));
17935    }
17936
17937    pub fn minimap(&self) -> Option<&Entity<Self>> {
17938        self.minimap
17939            .as_ref()
17940            .filter(|_| self.minimap_visibility.visible())
17941    }
17942
17943    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17944        let mut wrap_guides = smallvec![];
17945
17946        if self.show_wrap_guides == Some(false) {
17947            return wrap_guides;
17948        }
17949
17950        let settings = self.buffer.read(cx).language_settings(cx);
17951        if settings.show_wrap_guides {
17952            match self.soft_wrap_mode(cx) {
17953                SoftWrap::Column(soft_wrap) => {
17954                    wrap_guides.push((soft_wrap as usize, true));
17955                }
17956                SoftWrap::Bounded(soft_wrap) => {
17957                    wrap_guides.push((soft_wrap as usize, true));
17958                }
17959                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17960            }
17961            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17962        }
17963
17964        wrap_guides
17965    }
17966
17967    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17968        let settings = self.buffer.read(cx).language_settings(cx);
17969        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17970        match mode {
17971            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17972                SoftWrap::None
17973            }
17974            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17975            language_settings::SoftWrap::PreferredLineLength => {
17976                SoftWrap::Column(settings.preferred_line_length)
17977            }
17978            language_settings::SoftWrap::Bounded => {
17979                SoftWrap::Bounded(settings.preferred_line_length)
17980            }
17981        }
17982    }
17983
17984    pub fn set_soft_wrap_mode(
17985        &mut self,
17986        mode: language_settings::SoftWrap,
17987
17988        cx: &mut Context<Self>,
17989    ) {
17990        self.soft_wrap_mode_override = Some(mode);
17991        cx.notify();
17992    }
17993
17994    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17995        self.hard_wrap = hard_wrap;
17996        cx.notify();
17997    }
17998
17999    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18000        self.text_style_refinement = Some(style);
18001    }
18002
18003    /// called by the Element so we know what style we were most recently rendered with.
18004    pub(crate) fn set_style(
18005        &mut self,
18006        style: EditorStyle,
18007        window: &mut Window,
18008        cx: &mut Context<Self>,
18009    ) {
18010        // We intentionally do not inform the display map about the minimap style
18011        // so that wrapping is not recalculated and stays consistent for the editor
18012        // and its linked minimap.
18013        if !self.mode.is_minimap() {
18014            let rem_size = window.rem_size();
18015            self.display_map.update(cx, |map, cx| {
18016                map.set_font(
18017                    style.text.font(),
18018                    style.text.font_size.to_pixels(rem_size),
18019                    cx,
18020                )
18021            });
18022        }
18023        self.style = Some(style);
18024    }
18025
18026    pub fn style(&self) -> Option<&EditorStyle> {
18027        self.style.as_ref()
18028    }
18029
18030    // Called by the element. This method is not designed to be called outside of the editor
18031    // element's layout code because it does not notify when rewrapping is computed synchronously.
18032    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18033        self.display_map
18034            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18035    }
18036
18037    pub fn set_soft_wrap(&mut self) {
18038        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18039    }
18040
18041    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18042        if self.soft_wrap_mode_override.is_some() {
18043            self.soft_wrap_mode_override.take();
18044        } else {
18045            let soft_wrap = match self.soft_wrap_mode(cx) {
18046                SoftWrap::GitDiff => return,
18047                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18048                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18049                    language_settings::SoftWrap::None
18050                }
18051            };
18052            self.soft_wrap_mode_override = Some(soft_wrap);
18053        }
18054        cx.notify();
18055    }
18056
18057    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18058        let Some(workspace) = self.workspace() else {
18059            return;
18060        };
18061        let fs = workspace.read(cx).app_state().fs.clone();
18062        let current_show = TabBarSettings::get_global(cx).show;
18063        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18064            setting.show = Some(!current_show);
18065        });
18066    }
18067
18068    pub fn toggle_indent_guides(
18069        &mut self,
18070        _: &ToggleIndentGuides,
18071        _: &mut Window,
18072        cx: &mut Context<Self>,
18073    ) {
18074        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18075            self.buffer
18076                .read(cx)
18077                .language_settings(cx)
18078                .indent_guides
18079                .enabled
18080        });
18081        self.show_indent_guides = Some(!currently_enabled);
18082        cx.notify();
18083    }
18084
18085    fn should_show_indent_guides(&self) -> Option<bool> {
18086        self.show_indent_guides
18087    }
18088
18089    pub fn toggle_line_numbers(
18090        &mut self,
18091        _: &ToggleLineNumbers,
18092        _: &mut Window,
18093        cx: &mut Context<Self>,
18094    ) {
18095        let mut editor_settings = EditorSettings::get_global(cx).clone();
18096        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18097        EditorSettings::override_global(editor_settings, cx);
18098    }
18099
18100    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18101        if let Some(show_line_numbers) = self.show_line_numbers {
18102            return show_line_numbers;
18103        }
18104        EditorSettings::get_global(cx).gutter.line_numbers
18105    }
18106
18107    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18108        self.use_relative_line_numbers
18109            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18110    }
18111
18112    pub fn toggle_relative_line_numbers(
18113        &mut self,
18114        _: &ToggleRelativeLineNumbers,
18115        _: &mut Window,
18116        cx: &mut Context<Self>,
18117    ) {
18118        let is_relative = self.should_use_relative_line_numbers(cx);
18119        self.set_relative_line_number(Some(!is_relative), cx)
18120    }
18121
18122    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18123        self.use_relative_line_numbers = is_relative;
18124        cx.notify();
18125    }
18126
18127    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18128        self.show_gutter = show_gutter;
18129        cx.notify();
18130    }
18131
18132    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18133        self.show_scrollbars = ScrollbarAxes {
18134            horizontal: show,
18135            vertical: show,
18136        };
18137        cx.notify();
18138    }
18139
18140    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18141        self.show_scrollbars.vertical = show;
18142        cx.notify();
18143    }
18144
18145    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18146        self.show_scrollbars.horizontal = show;
18147        cx.notify();
18148    }
18149
18150    pub fn set_minimap_visibility(
18151        &mut self,
18152        minimap_visibility: MinimapVisibility,
18153        window: &mut Window,
18154        cx: &mut Context<Self>,
18155    ) {
18156        if self.minimap_visibility != minimap_visibility {
18157            if minimap_visibility.visible() && self.minimap.is_none() {
18158                let minimap_settings = EditorSettings::get_global(cx).minimap;
18159                self.minimap =
18160                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18161            }
18162            self.minimap_visibility = minimap_visibility;
18163            cx.notify();
18164        }
18165    }
18166
18167    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18168        self.set_show_scrollbars(false, cx);
18169        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18170    }
18171
18172    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18173        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18174    }
18175
18176    /// Normally the text in full mode and auto height editors is padded on the
18177    /// left side by roughly half a character width for improved hit testing.
18178    ///
18179    /// Use this method to disable this for cases where this is not wanted (e.g.
18180    /// if you want to align the editor text with some other text above or below)
18181    /// or if you want to add this padding to single-line editors.
18182    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18183        self.offset_content = offset_content;
18184        cx.notify();
18185    }
18186
18187    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18188        self.show_line_numbers = Some(show_line_numbers);
18189        cx.notify();
18190    }
18191
18192    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18193        self.disable_expand_excerpt_buttons = true;
18194        cx.notify();
18195    }
18196
18197    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18198        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18199        cx.notify();
18200    }
18201
18202    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18203        self.show_code_actions = Some(show_code_actions);
18204        cx.notify();
18205    }
18206
18207    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18208        self.show_runnables = Some(show_runnables);
18209        cx.notify();
18210    }
18211
18212    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18213        self.show_breakpoints = Some(show_breakpoints);
18214        cx.notify();
18215    }
18216
18217    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18218        if self.display_map.read(cx).masked != masked {
18219            self.display_map.update(cx, |map, _| map.masked = masked);
18220        }
18221        cx.notify()
18222    }
18223
18224    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18225        self.show_wrap_guides = Some(show_wrap_guides);
18226        cx.notify();
18227    }
18228
18229    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18230        self.show_indent_guides = Some(show_indent_guides);
18231        cx.notify();
18232    }
18233
18234    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18235        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18236            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18237                if let Some(dir) = file.abs_path(cx).parent() {
18238                    return Some(dir.to_owned());
18239                }
18240            }
18241
18242            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18243                return Some(project_path.path.to_path_buf());
18244            }
18245        }
18246
18247        None
18248    }
18249
18250    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18251        self.active_excerpt(cx)?
18252            .1
18253            .read(cx)
18254            .file()
18255            .and_then(|f| f.as_local())
18256    }
18257
18258    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18259        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18260            let buffer = buffer.read(cx);
18261            if let Some(project_path) = buffer.project_path(cx) {
18262                let project = self.project.as_ref()?.read(cx);
18263                project.absolute_path(&project_path, cx)
18264            } else {
18265                buffer
18266                    .file()
18267                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18268            }
18269        })
18270    }
18271
18272    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18273        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18274            let project_path = buffer.read(cx).project_path(cx)?;
18275            let project = self.project.as_ref()?.read(cx);
18276            let entry = project.entry_for_path(&project_path, cx)?;
18277            let path = entry.path.to_path_buf();
18278            Some(path)
18279        })
18280    }
18281
18282    pub fn reveal_in_finder(
18283        &mut self,
18284        _: &RevealInFileManager,
18285        _window: &mut Window,
18286        cx: &mut Context<Self>,
18287    ) {
18288        if let Some(target) = self.target_file(cx) {
18289            cx.reveal_path(&target.abs_path(cx));
18290        }
18291    }
18292
18293    pub fn copy_path(
18294        &mut self,
18295        _: &zed_actions::workspace::CopyPath,
18296        _window: &mut Window,
18297        cx: &mut Context<Self>,
18298    ) {
18299        if let Some(path) = self.target_file_abs_path(cx) {
18300            if let Some(path) = path.to_str() {
18301                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18302            }
18303        }
18304    }
18305
18306    pub fn copy_relative_path(
18307        &mut self,
18308        _: &zed_actions::workspace::CopyRelativePath,
18309        _window: &mut Window,
18310        cx: &mut Context<Self>,
18311    ) {
18312        if let Some(path) = self.target_file_path(cx) {
18313            if let Some(path) = path.to_str() {
18314                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18315            }
18316        }
18317    }
18318
18319    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18320        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18321            buffer.read(cx).project_path(cx)
18322        } else {
18323            None
18324        }
18325    }
18326
18327    // Returns true if the editor handled a go-to-line request
18328    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18329        maybe!({
18330            let breakpoint_store = self.breakpoint_store.as_ref()?;
18331
18332            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18333            else {
18334                self.clear_row_highlights::<ActiveDebugLine>();
18335                return None;
18336            };
18337
18338            let position = active_stack_frame.position;
18339            let buffer_id = position.buffer_id?;
18340            let snapshot = self
18341                .project
18342                .as_ref()?
18343                .read(cx)
18344                .buffer_for_id(buffer_id, cx)?
18345                .read(cx)
18346                .snapshot();
18347
18348            let mut handled = false;
18349            for (id, ExcerptRange { context, .. }) in
18350                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18351            {
18352                if context.start.cmp(&position, &snapshot).is_ge()
18353                    || context.end.cmp(&position, &snapshot).is_lt()
18354                {
18355                    continue;
18356                }
18357                let snapshot = self.buffer.read(cx).snapshot(cx);
18358                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18359
18360                handled = true;
18361                self.clear_row_highlights::<ActiveDebugLine>();
18362
18363                self.go_to_line::<ActiveDebugLine>(
18364                    multibuffer_anchor,
18365                    Some(cx.theme().colors().editor_debugger_active_line_background),
18366                    window,
18367                    cx,
18368                );
18369
18370                cx.notify();
18371            }
18372
18373            handled.then_some(())
18374        })
18375        .is_some()
18376    }
18377
18378    pub fn copy_file_name_without_extension(
18379        &mut self,
18380        _: &CopyFileNameWithoutExtension,
18381        _: &mut Window,
18382        cx: &mut Context<Self>,
18383    ) {
18384        if let Some(file) = self.target_file(cx) {
18385            if let Some(file_stem) = file.path().file_stem() {
18386                if let Some(name) = file_stem.to_str() {
18387                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18388                }
18389            }
18390        }
18391    }
18392
18393    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18394        if let Some(file) = self.target_file(cx) {
18395            if let Some(file_name) = file.path().file_name() {
18396                if let Some(name) = file_name.to_str() {
18397                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18398                }
18399            }
18400        }
18401    }
18402
18403    pub fn toggle_git_blame(
18404        &mut self,
18405        _: &::git::Blame,
18406        window: &mut Window,
18407        cx: &mut Context<Self>,
18408    ) {
18409        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18410
18411        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18412            self.start_git_blame(true, window, cx);
18413        }
18414
18415        cx.notify();
18416    }
18417
18418    pub fn toggle_git_blame_inline(
18419        &mut self,
18420        _: &ToggleGitBlameInline,
18421        window: &mut Window,
18422        cx: &mut Context<Self>,
18423    ) {
18424        self.toggle_git_blame_inline_internal(true, window, cx);
18425        cx.notify();
18426    }
18427
18428    pub fn open_git_blame_commit(
18429        &mut self,
18430        _: &OpenGitBlameCommit,
18431        window: &mut Window,
18432        cx: &mut Context<Self>,
18433    ) {
18434        self.open_git_blame_commit_internal(window, cx);
18435    }
18436
18437    fn open_git_blame_commit_internal(
18438        &mut self,
18439        window: &mut Window,
18440        cx: &mut Context<Self>,
18441    ) -> Option<()> {
18442        let blame = self.blame.as_ref()?;
18443        let snapshot = self.snapshot(window, cx);
18444        let cursor = self.selections.newest::<Point>(cx).head();
18445        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18446        let blame_entry = blame
18447            .update(cx, |blame, cx| {
18448                blame
18449                    .blame_for_rows(
18450                        &[RowInfo {
18451                            buffer_id: Some(buffer.remote_id()),
18452                            buffer_row: Some(point.row),
18453                            ..Default::default()
18454                        }],
18455                        cx,
18456                    )
18457                    .next()
18458            })
18459            .flatten()?;
18460        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18461        let repo = blame.read(cx).repository(cx)?;
18462        let workspace = self.workspace()?.downgrade();
18463        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18464        None
18465    }
18466
18467    pub fn git_blame_inline_enabled(&self) -> bool {
18468        self.git_blame_inline_enabled
18469    }
18470
18471    pub fn toggle_selection_menu(
18472        &mut self,
18473        _: &ToggleSelectionMenu,
18474        _: &mut Window,
18475        cx: &mut Context<Self>,
18476    ) {
18477        self.show_selection_menu = self
18478            .show_selection_menu
18479            .map(|show_selections_menu| !show_selections_menu)
18480            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18481
18482        cx.notify();
18483    }
18484
18485    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18486        self.show_selection_menu
18487            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18488    }
18489
18490    fn start_git_blame(
18491        &mut self,
18492        user_triggered: bool,
18493        window: &mut Window,
18494        cx: &mut Context<Self>,
18495    ) {
18496        if let Some(project) = self.project.as_ref() {
18497            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18498                return;
18499            };
18500
18501            if buffer.read(cx).file().is_none() {
18502                return;
18503            }
18504
18505            let focused = self.focus_handle(cx).contains_focused(window, cx);
18506
18507            let project = project.clone();
18508            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18509            self.blame_subscription =
18510                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18511            self.blame = Some(blame);
18512        }
18513    }
18514
18515    fn toggle_git_blame_inline_internal(
18516        &mut self,
18517        user_triggered: bool,
18518        window: &mut Window,
18519        cx: &mut Context<Self>,
18520    ) {
18521        if self.git_blame_inline_enabled {
18522            self.git_blame_inline_enabled = false;
18523            self.show_git_blame_inline = false;
18524            self.show_git_blame_inline_delay_task.take();
18525        } else {
18526            self.git_blame_inline_enabled = true;
18527            self.start_git_blame_inline(user_triggered, window, cx);
18528        }
18529
18530        cx.notify();
18531    }
18532
18533    fn start_git_blame_inline(
18534        &mut self,
18535        user_triggered: bool,
18536        window: &mut Window,
18537        cx: &mut Context<Self>,
18538    ) {
18539        self.start_git_blame(user_triggered, window, cx);
18540
18541        if ProjectSettings::get_global(cx)
18542            .git
18543            .inline_blame_delay()
18544            .is_some()
18545        {
18546            self.start_inline_blame_timer(window, cx);
18547        } else {
18548            self.show_git_blame_inline = true
18549        }
18550    }
18551
18552    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18553        self.blame.as_ref()
18554    }
18555
18556    pub fn show_git_blame_gutter(&self) -> bool {
18557        self.show_git_blame_gutter
18558    }
18559
18560    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18561        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18562    }
18563
18564    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18565        self.show_git_blame_inline
18566            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18567            && !self.newest_selection_head_on_empty_line(cx)
18568            && self.has_blame_entries(cx)
18569    }
18570
18571    fn has_blame_entries(&self, cx: &App) -> bool {
18572        self.blame()
18573            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18574    }
18575
18576    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18577        let cursor_anchor = self.selections.newest_anchor().head();
18578
18579        let snapshot = self.buffer.read(cx).snapshot(cx);
18580        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18581
18582        snapshot.line_len(buffer_row) == 0
18583    }
18584
18585    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18586        let buffer_and_selection = maybe!({
18587            let selection = self.selections.newest::<Point>(cx);
18588            let selection_range = selection.range();
18589
18590            let multi_buffer = self.buffer().read(cx);
18591            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18592            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18593
18594            let (buffer, range, _) = if selection.reversed {
18595                buffer_ranges.first()
18596            } else {
18597                buffer_ranges.last()
18598            }?;
18599
18600            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18601                ..text::ToPoint::to_point(&range.end, &buffer).row;
18602            Some((
18603                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18604                selection,
18605            ))
18606        });
18607
18608        let Some((buffer, selection)) = buffer_and_selection else {
18609            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18610        };
18611
18612        let Some(project) = self.project.as_ref() else {
18613            return Task::ready(Err(anyhow!("editor does not have project")));
18614        };
18615
18616        project.update(cx, |project, cx| {
18617            project.get_permalink_to_line(&buffer, selection, cx)
18618        })
18619    }
18620
18621    pub fn copy_permalink_to_line(
18622        &mut self,
18623        _: &CopyPermalinkToLine,
18624        window: &mut Window,
18625        cx: &mut Context<Self>,
18626    ) {
18627        let permalink_task = self.get_permalink_to_line(cx);
18628        let workspace = self.workspace();
18629
18630        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18631            Ok(permalink) => {
18632                cx.update(|_, cx| {
18633                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18634                })
18635                .ok();
18636            }
18637            Err(err) => {
18638                let message = format!("Failed to copy permalink: {err}");
18639
18640                anyhow::Result::<()>::Err(err).log_err();
18641
18642                if let Some(workspace) = workspace {
18643                    workspace
18644                        .update_in(cx, |workspace, _, cx| {
18645                            struct CopyPermalinkToLine;
18646
18647                            workspace.show_toast(
18648                                Toast::new(
18649                                    NotificationId::unique::<CopyPermalinkToLine>(),
18650                                    message,
18651                                ),
18652                                cx,
18653                            )
18654                        })
18655                        .ok();
18656                }
18657            }
18658        })
18659        .detach();
18660    }
18661
18662    pub fn copy_file_location(
18663        &mut self,
18664        _: &CopyFileLocation,
18665        _: &mut Window,
18666        cx: &mut Context<Self>,
18667    ) {
18668        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18669        if let Some(file) = self.target_file(cx) {
18670            if let Some(path) = file.path().to_str() {
18671                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18672            }
18673        }
18674    }
18675
18676    pub fn open_permalink_to_line(
18677        &mut self,
18678        _: &OpenPermalinkToLine,
18679        window: &mut Window,
18680        cx: &mut Context<Self>,
18681    ) {
18682        let permalink_task = self.get_permalink_to_line(cx);
18683        let workspace = self.workspace();
18684
18685        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18686            Ok(permalink) => {
18687                cx.update(|_, cx| {
18688                    cx.open_url(permalink.as_ref());
18689                })
18690                .ok();
18691            }
18692            Err(err) => {
18693                let message = format!("Failed to open permalink: {err}");
18694
18695                anyhow::Result::<()>::Err(err).log_err();
18696
18697                if let Some(workspace) = workspace {
18698                    workspace
18699                        .update(cx, |workspace, cx| {
18700                            struct OpenPermalinkToLine;
18701
18702                            workspace.show_toast(
18703                                Toast::new(
18704                                    NotificationId::unique::<OpenPermalinkToLine>(),
18705                                    message,
18706                                ),
18707                                cx,
18708                            )
18709                        })
18710                        .ok();
18711                }
18712            }
18713        })
18714        .detach();
18715    }
18716
18717    pub fn insert_uuid_v4(
18718        &mut self,
18719        _: &InsertUuidV4,
18720        window: &mut Window,
18721        cx: &mut Context<Self>,
18722    ) {
18723        self.insert_uuid(UuidVersion::V4, window, cx);
18724    }
18725
18726    pub fn insert_uuid_v7(
18727        &mut self,
18728        _: &InsertUuidV7,
18729        window: &mut Window,
18730        cx: &mut Context<Self>,
18731    ) {
18732        self.insert_uuid(UuidVersion::V7, window, cx);
18733    }
18734
18735    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18736        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18737        self.transact(window, cx, |this, window, cx| {
18738            let edits = this
18739                .selections
18740                .all::<Point>(cx)
18741                .into_iter()
18742                .map(|selection| {
18743                    let uuid = match version {
18744                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18745                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18746                    };
18747
18748                    (selection.range(), uuid.to_string())
18749                });
18750            this.edit(edits, cx);
18751            this.refresh_inline_completion(true, false, window, cx);
18752        });
18753    }
18754
18755    pub fn open_selections_in_multibuffer(
18756        &mut self,
18757        _: &OpenSelectionsInMultibuffer,
18758        window: &mut Window,
18759        cx: &mut Context<Self>,
18760    ) {
18761        let multibuffer = self.buffer.read(cx);
18762
18763        let Some(buffer) = multibuffer.as_singleton() else {
18764            return;
18765        };
18766
18767        let Some(workspace) = self.workspace() else {
18768            return;
18769        };
18770
18771        let title = multibuffer.title(cx).to_string();
18772
18773        let locations = self
18774            .selections
18775            .all_anchors(cx)
18776            .into_iter()
18777            .map(|selection| Location {
18778                buffer: buffer.clone(),
18779                range: selection.start.text_anchor..selection.end.text_anchor,
18780            })
18781            .collect::<Vec<_>>();
18782
18783        cx.spawn_in(window, async move |_, cx| {
18784            workspace.update_in(cx, |workspace, window, cx| {
18785                Self::open_locations_in_multibuffer(
18786                    workspace,
18787                    locations,
18788                    format!("Selections for '{title}'"),
18789                    false,
18790                    MultibufferSelectionMode::All,
18791                    window,
18792                    cx,
18793                );
18794            })
18795        })
18796        .detach();
18797    }
18798
18799    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18800    /// last highlight added will be used.
18801    ///
18802    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18803    pub fn highlight_rows<T: 'static>(
18804        &mut self,
18805        range: Range<Anchor>,
18806        color: Hsla,
18807        options: RowHighlightOptions,
18808        cx: &mut Context<Self>,
18809    ) {
18810        let snapshot = self.buffer().read(cx).snapshot(cx);
18811        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18812        let ix = row_highlights.binary_search_by(|highlight| {
18813            Ordering::Equal
18814                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18815                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18816        });
18817
18818        if let Err(mut ix) = ix {
18819            let index = post_inc(&mut self.highlight_order);
18820
18821            // If this range intersects with the preceding highlight, then merge it with
18822            // the preceding highlight. Otherwise insert a new highlight.
18823            let mut merged = false;
18824            if ix > 0 {
18825                let prev_highlight = &mut row_highlights[ix - 1];
18826                if prev_highlight
18827                    .range
18828                    .end
18829                    .cmp(&range.start, &snapshot)
18830                    .is_ge()
18831                {
18832                    ix -= 1;
18833                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18834                        prev_highlight.range.end = range.end;
18835                    }
18836                    merged = true;
18837                    prev_highlight.index = index;
18838                    prev_highlight.color = color;
18839                    prev_highlight.options = options;
18840                }
18841            }
18842
18843            if !merged {
18844                row_highlights.insert(
18845                    ix,
18846                    RowHighlight {
18847                        range: range.clone(),
18848                        index,
18849                        color,
18850                        options,
18851                        type_id: TypeId::of::<T>(),
18852                    },
18853                );
18854            }
18855
18856            // If any of the following highlights intersect with this one, merge them.
18857            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18858                let highlight = &row_highlights[ix];
18859                if next_highlight
18860                    .range
18861                    .start
18862                    .cmp(&highlight.range.end, &snapshot)
18863                    .is_le()
18864                {
18865                    if next_highlight
18866                        .range
18867                        .end
18868                        .cmp(&highlight.range.end, &snapshot)
18869                        .is_gt()
18870                    {
18871                        row_highlights[ix].range.end = next_highlight.range.end;
18872                    }
18873                    row_highlights.remove(ix + 1);
18874                } else {
18875                    break;
18876                }
18877            }
18878        }
18879    }
18880
18881    /// Remove any highlighted row ranges of the given type that intersect the
18882    /// given ranges.
18883    pub fn remove_highlighted_rows<T: 'static>(
18884        &mut self,
18885        ranges_to_remove: Vec<Range<Anchor>>,
18886        cx: &mut Context<Self>,
18887    ) {
18888        let snapshot = self.buffer().read(cx).snapshot(cx);
18889        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18890        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18891        row_highlights.retain(|highlight| {
18892            while let Some(range_to_remove) = ranges_to_remove.peek() {
18893                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18894                    Ordering::Less | Ordering::Equal => {
18895                        ranges_to_remove.next();
18896                    }
18897                    Ordering::Greater => {
18898                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18899                            Ordering::Less | Ordering::Equal => {
18900                                return false;
18901                            }
18902                            Ordering::Greater => break,
18903                        }
18904                    }
18905                }
18906            }
18907
18908            true
18909        })
18910    }
18911
18912    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18913    pub fn clear_row_highlights<T: 'static>(&mut self) {
18914        self.highlighted_rows.remove(&TypeId::of::<T>());
18915    }
18916
18917    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18918    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18919        self.highlighted_rows
18920            .get(&TypeId::of::<T>())
18921            .map_or(&[] as &[_], |vec| vec.as_slice())
18922            .iter()
18923            .map(|highlight| (highlight.range.clone(), highlight.color))
18924    }
18925
18926    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18927    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18928    /// Allows to ignore certain kinds of highlights.
18929    pub fn highlighted_display_rows(
18930        &self,
18931        window: &mut Window,
18932        cx: &mut App,
18933    ) -> BTreeMap<DisplayRow, LineHighlight> {
18934        let snapshot = self.snapshot(window, cx);
18935        let mut used_highlight_orders = HashMap::default();
18936        self.highlighted_rows
18937            .iter()
18938            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18939            .fold(
18940                BTreeMap::<DisplayRow, LineHighlight>::new(),
18941                |mut unique_rows, highlight| {
18942                    let start = highlight.range.start.to_display_point(&snapshot);
18943                    let end = highlight.range.end.to_display_point(&snapshot);
18944                    let start_row = start.row().0;
18945                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18946                        && end.column() == 0
18947                    {
18948                        end.row().0.saturating_sub(1)
18949                    } else {
18950                        end.row().0
18951                    };
18952                    for row in start_row..=end_row {
18953                        let used_index =
18954                            used_highlight_orders.entry(row).or_insert(highlight.index);
18955                        if highlight.index >= *used_index {
18956                            *used_index = highlight.index;
18957                            unique_rows.insert(
18958                                DisplayRow(row),
18959                                LineHighlight {
18960                                    include_gutter: highlight.options.include_gutter,
18961                                    border: None,
18962                                    background: highlight.color.into(),
18963                                    type_id: Some(highlight.type_id),
18964                                },
18965                            );
18966                        }
18967                    }
18968                    unique_rows
18969                },
18970            )
18971    }
18972
18973    pub fn highlighted_display_row_for_autoscroll(
18974        &self,
18975        snapshot: &DisplaySnapshot,
18976    ) -> Option<DisplayRow> {
18977        self.highlighted_rows
18978            .values()
18979            .flat_map(|highlighted_rows| highlighted_rows.iter())
18980            .filter_map(|highlight| {
18981                if highlight.options.autoscroll {
18982                    Some(highlight.range.start.to_display_point(snapshot).row())
18983                } else {
18984                    None
18985                }
18986            })
18987            .min()
18988    }
18989
18990    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18991        self.highlight_background::<SearchWithinRange>(
18992            ranges,
18993            |colors| colors.colors().editor_document_highlight_read_background,
18994            cx,
18995        )
18996    }
18997
18998    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18999        self.breadcrumb_header = Some(new_header);
19000    }
19001
19002    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19003        self.clear_background_highlights::<SearchWithinRange>(cx);
19004    }
19005
19006    pub fn highlight_background<T: 'static>(
19007        &mut self,
19008        ranges: &[Range<Anchor>],
19009        color_fetcher: fn(&Theme) -> Hsla,
19010        cx: &mut Context<Self>,
19011    ) {
19012        self.background_highlights.insert(
19013            HighlightKey::Type(TypeId::of::<T>()),
19014            (color_fetcher, Arc::from(ranges)),
19015        );
19016        self.scrollbar_marker_state.dirty = true;
19017        cx.notify();
19018    }
19019
19020    pub fn highlight_background_key<T: 'static>(
19021        &mut self,
19022        key: usize,
19023        ranges: &[Range<Anchor>],
19024        color_fetcher: fn(&Theme) -> Hsla,
19025        cx: &mut Context<Self>,
19026    ) {
19027        self.background_highlights.insert(
19028            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19029            (color_fetcher, Arc::from(ranges)),
19030        );
19031        self.scrollbar_marker_state.dirty = true;
19032        cx.notify();
19033    }
19034
19035    pub fn clear_background_highlights<T: 'static>(
19036        &mut self,
19037        cx: &mut Context<Self>,
19038    ) -> Option<BackgroundHighlight> {
19039        let text_highlights = self
19040            .background_highlights
19041            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19042        if !text_highlights.1.is_empty() {
19043            self.scrollbar_marker_state.dirty = true;
19044            cx.notify();
19045        }
19046        Some(text_highlights)
19047    }
19048
19049    pub fn highlight_gutter<T: 'static>(
19050        &mut self,
19051        ranges: impl Into<Vec<Range<Anchor>>>,
19052        color_fetcher: fn(&App) -> Hsla,
19053        cx: &mut Context<Self>,
19054    ) {
19055        self.gutter_highlights
19056            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19057        cx.notify();
19058    }
19059
19060    pub fn clear_gutter_highlights<T: 'static>(
19061        &mut self,
19062        cx: &mut Context<Self>,
19063    ) -> Option<GutterHighlight> {
19064        cx.notify();
19065        self.gutter_highlights.remove(&TypeId::of::<T>())
19066    }
19067
19068    pub fn insert_gutter_highlight<T: 'static>(
19069        &mut self,
19070        range: Range<Anchor>,
19071        color_fetcher: fn(&App) -> Hsla,
19072        cx: &mut Context<Self>,
19073    ) {
19074        let snapshot = self.buffer().read(cx).snapshot(cx);
19075        let mut highlights = self
19076            .gutter_highlights
19077            .remove(&TypeId::of::<T>())
19078            .map(|(_, highlights)| highlights)
19079            .unwrap_or_default();
19080        let ix = highlights.binary_search_by(|highlight| {
19081            Ordering::Equal
19082                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19083                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19084        });
19085        if let Err(ix) = ix {
19086            highlights.insert(ix, range);
19087        }
19088        self.gutter_highlights
19089            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19090    }
19091
19092    pub fn remove_gutter_highlights<T: 'static>(
19093        &mut self,
19094        ranges_to_remove: Vec<Range<Anchor>>,
19095        cx: &mut Context<Self>,
19096    ) {
19097        let snapshot = self.buffer().read(cx).snapshot(cx);
19098        let Some((color_fetcher, mut gutter_highlights)) =
19099            self.gutter_highlights.remove(&TypeId::of::<T>())
19100        else {
19101            return;
19102        };
19103        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19104        gutter_highlights.retain(|highlight| {
19105            while let Some(range_to_remove) = ranges_to_remove.peek() {
19106                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19107                    Ordering::Less | Ordering::Equal => {
19108                        ranges_to_remove.next();
19109                    }
19110                    Ordering::Greater => {
19111                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19112                            Ordering::Less | Ordering::Equal => {
19113                                return false;
19114                            }
19115                            Ordering::Greater => break,
19116                        }
19117                    }
19118                }
19119            }
19120
19121            true
19122        });
19123        self.gutter_highlights
19124            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19125    }
19126
19127    #[cfg(feature = "test-support")]
19128    pub fn all_text_highlights(
19129        &self,
19130        window: &mut Window,
19131        cx: &mut Context<Self>,
19132    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19133        let snapshot = self.snapshot(window, cx);
19134        self.display_map.update(cx, |display_map, _| {
19135            display_map
19136                .all_text_highlights()
19137                .map(|highlight| {
19138                    let (style, ranges) = highlight.as_ref();
19139                    (
19140                        *style,
19141                        ranges
19142                            .iter()
19143                            .map(|range| range.clone().to_display_points(&snapshot))
19144                            .collect(),
19145                    )
19146                })
19147                .collect()
19148        })
19149    }
19150
19151    #[cfg(feature = "test-support")]
19152    pub fn all_text_background_highlights(
19153        &self,
19154        window: &mut Window,
19155        cx: &mut Context<Self>,
19156    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19157        let snapshot = self.snapshot(window, cx);
19158        let buffer = &snapshot.buffer_snapshot;
19159        let start = buffer.anchor_before(0);
19160        let end = buffer.anchor_after(buffer.len());
19161        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19162    }
19163
19164    #[cfg(feature = "test-support")]
19165    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19166        let snapshot = self.buffer().read(cx).snapshot(cx);
19167
19168        let highlights = self
19169            .background_highlights
19170            .get(&HighlightKey::Type(TypeId::of::<
19171                items::BufferSearchHighlights,
19172            >()));
19173
19174        if let Some((_color, ranges)) = highlights {
19175            ranges
19176                .iter()
19177                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19178                .collect_vec()
19179        } else {
19180            vec![]
19181        }
19182    }
19183
19184    fn document_highlights_for_position<'a>(
19185        &'a self,
19186        position: Anchor,
19187        buffer: &'a MultiBufferSnapshot,
19188    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19189        let read_highlights = self
19190            .background_highlights
19191            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19192            .map(|h| &h.1);
19193        let write_highlights = self
19194            .background_highlights
19195            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19196            .map(|h| &h.1);
19197        let left_position = position.bias_left(buffer);
19198        let right_position = position.bias_right(buffer);
19199        read_highlights
19200            .into_iter()
19201            .chain(write_highlights)
19202            .flat_map(move |ranges| {
19203                let start_ix = match ranges.binary_search_by(|probe| {
19204                    let cmp = probe.end.cmp(&left_position, buffer);
19205                    if cmp.is_ge() {
19206                        Ordering::Greater
19207                    } else {
19208                        Ordering::Less
19209                    }
19210                }) {
19211                    Ok(i) | Err(i) => i,
19212                };
19213
19214                ranges[start_ix..]
19215                    .iter()
19216                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19217            })
19218    }
19219
19220    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19221        self.background_highlights
19222            .get(&HighlightKey::Type(TypeId::of::<T>()))
19223            .map_or(false, |(_, highlights)| !highlights.is_empty())
19224    }
19225
19226    pub fn background_highlights_in_range(
19227        &self,
19228        search_range: Range<Anchor>,
19229        display_snapshot: &DisplaySnapshot,
19230        theme: &Theme,
19231    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19232        let mut results = Vec::new();
19233        for (color_fetcher, ranges) in self.background_highlights.values() {
19234            let color = color_fetcher(theme);
19235            let start_ix = match ranges.binary_search_by(|probe| {
19236                let cmp = probe
19237                    .end
19238                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19239                if cmp.is_gt() {
19240                    Ordering::Greater
19241                } else {
19242                    Ordering::Less
19243                }
19244            }) {
19245                Ok(i) | Err(i) => i,
19246            };
19247            for range in &ranges[start_ix..] {
19248                if range
19249                    .start
19250                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19251                    .is_ge()
19252                {
19253                    break;
19254                }
19255
19256                let start = range.start.to_display_point(display_snapshot);
19257                let end = range.end.to_display_point(display_snapshot);
19258                results.push((start..end, color))
19259            }
19260        }
19261        results
19262    }
19263
19264    pub fn background_highlight_row_ranges<T: 'static>(
19265        &self,
19266        search_range: Range<Anchor>,
19267        display_snapshot: &DisplaySnapshot,
19268        count: usize,
19269    ) -> Vec<RangeInclusive<DisplayPoint>> {
19270        let mut results = Vec::new();
19271        let Some((_, ranges)) = self
19272            .background_highlights
19273            .get(&HighlightKey::Type(TypeId::of::<T>()))
19274        else {
19275            return vec![];
19276        };
19277
19278        let start_ix = match ranges.binary_search_by(|probe| {
19279            let cmp = probe
19280                .end
19281                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19282            if cmp.is_gt() {
19283                Ordering::Greater
19284            } else {
19285                Ordering::Less
19286            }
19287        }) {
19288            Ok(i) | Err(i) => i,
19289        };
19290        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19291            if let (Some(start_display), Some(end_display)) = (start, end) {
19292                results.push(
19293                    start_display.to_display_point(display_snapshot)
19294                        ..=end_display.to_display_point(display_snapshot),
19295                );
19296            }
19297        };
19298        let mut start_row: Option<Point> = None;
19299        let mut end_row: Option<Point> = None;
19300        if ranges.len() > count {
19301            return Vec::new();
19302        }
19303        for range in &ranges[start_ix..] {
19304            if range
19305                .start
19306                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19307                .is_ge()
19308            {
19309                break;
19310            }
19311            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19312            if let Some(current_row) = &end_row {
19313                if end.row == current_row.row {
19314                    continue;
19315                }
19316            }
19317            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19318            if start_row.is_none() {
19319                assert_eq!(end_row, None);
19320                start_row = Some(start);
19321                end_row = Some(end);
19322                continue;
19323            }
19324            if let Some(current_end) = end_row.as_mut() {
19325                if start.row > current_end.row + 1 {
19326                    push_region(start_row, end_row);
19327                    start_row = Some(start);
19328                    end_row = Some(end);
19329                } else {
19330                    // Merge two hunks.
19331                    *current_end = end;
19332                }
19333            } else {
19334                unreachable!();
19335            }
19336        }
19337        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19338        push_region(start_row, end_row);
19339        results
19340    }
19341
19342    pub fn gutter_highlights_in_range(
19343        &self,
19344        search_range: Range<Anchor>,
19345        display_snapshot: &DisplaySnapshot,
19346        cx: &App,
19347    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19348        let mut results = Vec::new();
19349        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19350            let color = color_fetcher(cx);
19351            let start_ix = match ranges.binary_search_by(|probe| {
19352                let cmp = probe
19353                    .end
19354                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19355                if cmp.is_gt() {
19356                    Ordering::Greater
19357                } else {
19358                    Ordering::Less
19359                }
19360            }) {
19361                Ok(i) | Err(i) => i,
19362            };
19363            for range in &ranges[start_ix..] {
19364                if range
19365                    .start
19366                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19367                    .is_ge()
19368                {
19369                    break;
19370                }
19371
19372                let start = range.start.to_display_point(display_snapshot);
19373                let end = range.end.to_display_point(display_snapshot);
19374                results.push((start..end, color))
19375            }
19376        }
19377        results
19378    }
19379
19380    /// Get the text ranges corresponding to the redaction query
19381    pub fn redacted_ranges(
19382        &self,
19383        search_range: Range<Anchor>,
19384        display_snapshot: &DisplaySnapshot,
19385        cx: &App,
19386    ) -> Vec<Range<DisplayPoint>> {
19387        display_snapshot
19388            .buffer_snapshot
19389            .redacted_ranges(search_range, |file| {
19390                if let Some(file) = file {
19391                    file.is_private()
19392                        && EditorSettings::get(
19393                            Some(SettingsLocation {
19394                                worktree_id: file.worktree_id(cx),
19395                                path: file.path().as_ref(),
19396                            }),
19397                            cx,
19398                        )
19399                        .redact_private_values
19400                } else {
19401                    false
19402                }
19403            })
19404            .map(|range| {
19405                range.start.to_display_point(display_snapshot)
19406                    ..range.end.to_display_point(display_snapshot)
19407            })
19408            .collect()
19409    }
19410
19411    pub fn highlight_text_key<T: 'static>(
19412        &mut self,
19413        key: usize,
19414        ranges: Vec<Range<Anchor>>,
19415        style: HighlightStyle,
19416        cx: &mut Context<Self>,
19417    ) {
19418        self.display_map.update(cx, |map, _| {
19419            map.highlight_text(
19420                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19421                ranges,
19422                style,
19423            );
19424        });
19425        cx.notify();
19426    }
19427
19428    pub fn highlight_text<T: 'static>(
19429        &mut self,
19430        ranges: Vec<Range<Anchor>>,
19431        style: HighlightStyle,
19432        cx: &mut Context<Self>,
19433    ) {
19434        self.display_map.update(cx, |map, _| {
19435            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19436        });
19437        cx.notify();
19438    }
19439
19440    pub(crate) fn highlight_inlays<T: 'static>(
19441        &mut self,
19442        highlights: Vec<InlayHighlight>,
19443        style: HighlightStyle,
19444        cx: &mut Context<Self>,
19445    ) {
19446        self.display_map.update(cx, |map, _| {
19447            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19448        });
19449        cx.notify();
19450    }
19451
19452    pub fn text_highlights<'a, T: 'static>(
19453        &'a self,
19454        cx: &'a App,
19455    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19456        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19457    }
19458
19459    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19460        let cleared = self
19461            .display_map
19462            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19463        if cleared {
19464            cx.notify();
19465        }
19466    }
19467
19468    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19469        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19470            && self.focus_handle.is_focused(window)
19471    }
19472
19473    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19474        self.show_cursor_when_unfocused = is_enabled;
19475        cx.notify();
19476    }
19477
19478    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19479        cx.notify();
19480    }
19481
19482    fn on_debug_session_event(
19483        &mut self,
19484        _session: Entity<Session>,
19485        event: &SessionEvent,
19486        cx: &mut Context<Self>,
19487    ) {
19488        match event {
19489            SessionEvent::InvalidateInlineValue => {
19490                self.refresh_inline_values(cx);
19491            }
19492            _ => {}
19493        }
19494    }
19495
19496    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19497        let Some(project) = self.project.clone() else {
19498            return;
19499        };
19500
19501        if !self.inline_value_cache.enabled {
19502            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19503            self.splice_inlays(&inlays, Vec::new(), cx);
19504            return;
19505        }
19506
19507        let current_execution_position = self
19508            .highlighted_rows
19509            .get(&TypeId::of::<ActiveDebugLine>())
19510            .and_then(|lines| lines.last().map(|line| line.range.end));
19511
19512        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19513            let inline_values = editor
19514                .update(cx, |editor, cx| {
19515                    let Some(current_execution_position) = current_execution_position else {
19516                        return Some(Task::ready(Ok(Vec::new())));
19517                    };
19518
19519                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19520                        let snapshot = buffer.snapshot(cx);
19521
19522                        let excerpt = snapshot.excerpt_containing(
19523                            current_execution_position..current_execution_position,
19524                        )?;
19525
19526                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19527                    })?;
19528
19529                    let range =
19530                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19531
19532                    project.inline_values(buffer, range, cx)
19533                })
19534                .ok()
19535                .flatten()?
19536                .await
19537                .context("refreshing debugger inlays")
19538                .log_err()?;
19539
19540            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19541
19542            for (buffer_id, inline_value) in inline_values
19543                .into_iter()
19544                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19545            {
19546                buffer_inline_values
19547                    .entry(buffer_id)
19548                    .or_default()
19549                    .push(inline_value);
19550            }
19551
19552            editor
19553                .update(cx, |editor, cx| {
19554                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19555                    let mut new_inlays = Vec::default();
19556
19557                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19558                        let buffer_id = buffer_snapshot.remote_id();
19559                        buffer_inline_values
19560                            .get(&buffer_id)
19561                            .into_iter()
19562                            .flatten()
19563                            .for_each(|hint| {
19564                                let inlay = Inlay::debugger(
19565                                    post_inc(&mut editor.next_inlay_id),
19566                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19567                                    hint.text(),
19568                                );
19569
19570                                new_inlays.push(inlay);
19571                            });
19572                    }
19573
19574                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19575                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19576
19577                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19578                })
19579                .ok()?;
19580            Some(())
19581        });
19582    }
19583
19584    fn on_buffer_event(
19585        &mut self,
19586        multibuffer: &Entity<MultiBuffer>,
19587        event: &multi_buffer::Event,
19588        window: &mut Window,
19589        cx: &mut Context<Self>,
19590    ) {
19591        match event {
19592            multi_buffer::Event::Edited {
19593                singleton_buffer_edited,
19594                edited_buffer,
19595            } => {
19596                self.scrollbar_marker_state.dirty = true;
19597                self.active_indent_guides_state.dirty = true;
19598                self.refresh_active_diagnostics(cx);
19599                self.refresh_code_actions(window, cx);
19600                self.refresh_selected_text_highlights(true, window, cx);
19601                self.refresh_single_line_folds(window, cx);
19602                refresh_matching_bracket_highlights(self, window, cx);
19603                if self.has_active_inline_completion() {
19604                    self.update_visible_inline_completion(window, cx);
19605                }
19606                if let Some(project) = self.project.as_ref() {
19607                    if let Some(edited_buffer) = edited_buffer {
19608                        project.update(cx, |project, cx| {
19609                            self.registered_buffers
19610                                .entry(edited_buffer.read(cx).remote_id())
19611                                .or_insert_with(|| {
19612                                    project
19613                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19614                                });
19615                        });
19616                    }
19617                }
19618                cx.emit(EditorEvent::BufferEdited);
19619                cx.emit(SearchEvent::MatchesInvalidated);
19620
19621                if let Some(buffer) = edited_buffer {
19622                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19623                }
19624
19625                if *singleton_buffer_edited {
19626                    if let Some(buffer) = edited_buffer {
19627                        if buffer.read(cx).file().is_none() {
19628                            cx.emit(EditorEvent::TitleChanged);
19629                        }
19630                    }
19631                    if let Some(project) = &self.project {
19632                        #[allow(clippy::mutable_key_type)]
19633                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19634                            multibuffer
19635                                .all_buffers()
19636                                .into_iter()
19637                                .filter_map(|buffer| {
19638                                    buffer.update(cx, |buffer, cx| {
19639                                        let language = buffer.language()?;
19640                                        let should_discard = project.update(cx, |project, cx| {
19641                                            project.is_local()
19642                                                && !project.has_language_servers_for(buffer, cx)
19643                                        });
19644                                        should_discard.not().then_some(language.clone())
19645                                    })
19646                                })
19647                                .collect::<HashSet<_>>()
19648                        });
19649                        if !languages_affected.is_empty() {
19650                            self.refresh_inlay_hints(
19651                                InlayHintRefreshReason::BufferEdited(languages_affected),
19652                                cx,
19653                            );
19654                        }
19655                    }
19656                }
19657
19658                let Some(project) = &self.project else { return };
19659                let (telemetry, is_via_ssh) = {
19660                    let project = project.read(cx);
19661                    let telemetry = project.client().telemetry().clone();
19662                    let is_via_ssh = project.is_via_ssh();
19663                    (telemetry, is_via_ssh)
19664                };
19665                refresh_linked_ranges(self, window, cx);
19666                telemetry.log_edit_event("editor", is_via_ssh);
19667            }
19668            multi_buffer::Event::ExcerptsAdded {
19669                buffer,
19670                predecessor,
19671                excerpts,
19672            } => {
19673                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19674                let buffer_id = buffer.read(cx).remote_id();
19675                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19676                    if let Some(project) = &self.project {
19677                        update_uncommitted_diff_for_buffer(
19678                            cx.entity(),
19679                            project,
19680                            [buffer.clone()],
19681                            self.buffer.clone(),
19682                            cx,
19683                        )
19684                        .detach();
19685                    }
19686                }
19687                self.update_lsp_data(false, Some(buffer_id), window, cx);
19688                cx.emit(EditorEvent::ExcerptsAdded {
19689                    buffer: buffer.clone(),
19690                    predecessor: *predecessor,
19691                    excerpts: excerpts.clone(),
19692                });
19693                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19694            }
19695            multi_buffer::Event::ExcerptsRemoved {
19696                ids,
19697                removed_buffer_ids,
19698            } => {
19699                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19700                let buffer = self.buffer.read(cx);
19701                self.registered_buffers
19702                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19703                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19704                cx.emit(EditorEvent::ExcerptsRemoved {
19705                    ids: ids.clone(),
19706                    removed_buffer_ids: removed_buffer_ids.clone(),
19707                });
19708            }
19709            multi_buffer::Event::ExcerptsEdited {
19710                excerpt_ids,
19711                buffer_ids,
19712            } => {
19713                self.display_map.update(cx, |map, cx| {
19714                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19715                });
19716                cx.emit(EditorEvent::ExcerptsEdited {
19717                    ids: excerpt_ids.clone(),
19718                });
19719            }
19720            multi_buffer::Event::ExcerptsExpanded { ids } => {
19721                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19722                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19723            }
19724            multi_buffer::Event::Reparsed(buffer_id) => {
19725                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19726                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19727
19728                cx.emit(EditorEvent::Reparsed(*buffer_id));
19729            }
19730            multi_buffer::Event::DiffHunksToggled => {
19731                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19732            }
19733            multi_buffer::Event::LanguageChanged(buffer_id) => {
19734                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19735                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19736                cx.emit(EditorEvent::Reparsed(*buffer_id));
19737                cx.notify();
19738            }
19739            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19740            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19741            multi_buffer::Event::FileHandleChanged
19742            | multi_buffer::Event::Reloaded
19743            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19744            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19745            multi_buffer::Event::DiagnosticsUpdated => {
19746                self.update_diagnostics_state(window, cx);
19747            }
19748            _ => {}
19749        };
19750    }
19751
19752    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19753        if !self.diagnostics_enabled() {
19754            return;
19755        }
19756        self.refresh_active_diagnostics(cx);
19757        self.refresh_inline_diagnostics(true, window, cx);
19758        self.scrollbar_marker_state.dirty = true;
19759        cx.notify();
19760    }
19761
19762    pub fn start_temporary_diff_override(&mut self) {
19763        self.load_diff_task.take();
19764        self.temporary_diff_override = true;
19765    }
19766
19767    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19768        self.temporary_diff_override = false;
19769        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19770        self.buffer.update(cx, |buffer, cx| {
19771            buffer.set_all_diff_hunks_collapsed(cx);
19772        });
19773
19774        if let Some(project) = self.project.clone() {
19775            self.load_diff_task = Some(
19776                update_uncommitted_diff_for_buffer(
19777                    cx.entity(),
19778                    &project,
19779                    self.buffer.read(cx).all_buffers(),
19780                    self.buffer.clone(),
19781                    cx,
19782                )
19783                .shared(),
19784            );
19785        }
19786    }
19787
19788    fn on_display_map_changed(
19789        &mut self,
19790        _: Entity<DisplayMap>,
19791        _: &mut Window,
19792        cx: &mut Context<Self>,
19793    ) {
19794        cx.notify();
19795    }
19796
19797    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19798        let new_severity = if self.diagnostics_enabled() {
19799            EditorSettings::get_global(cx)
19800                .diagnostics_max_severity
19801                .unwrap_or(DiagnosticSeverity::Hint)
19802        } else {
19803            DiagnosticSeverity::Off
19804        };
19805        self.set_max_diagnostics_severity(new_severity, cx);
19806        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19807        self.update_edit_prediction_settings(cx);
19808        self.refresh_inline_completion(true, false, window, cx);
19809        self.refresh_inlay_hints(
19810            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19811                self.selections.newest_anchor().head(),
19812                &self.buffer.read(cx).snapshot(cx),
19813                cx,
19814            )),
19815            cx,
19816        );
19817
19818        let old_cursor_shape = self.cursor_shape;
19819
19820        {
19821            let editor_settings = EditorSettings::get_global(cx);
19822            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19823            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19824            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19825            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19826            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19827        }
19828
19829        if old_cursor_shape != self.cursor_shape {
19830            cx.emit(EditorEvent::CursorShapeChanged);
19831        }
19832
19833        let project_settings = ProjectSettings::get_global(cx);
19834        self.serialize_dirty_buffers =
19835            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19836
19837        if self.mode.is_full() {
19838            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19839            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19840            if self.show_inline_diagnostics != show_inline_diagnostics {
19841                self.show_inline_diagnostics = show_inline_diagnostics;
19842                self.refresh_inline_diagnostics(false, window, cx);
19843            }
19844
19845            if self.git_blame_inline_enabled != inline_blame_enabled {
19846                self.toggle_git_blame_inline_internal(false, window, cx);
19847            }
19848
19849            let minimap_settings = EditorSettings::get_global(cx).minimap;
19850            if self.minimap_visibility != MinimapVisibility::Disabled {
19851                if self.minimap_visibility.settings_visibility()
19852                    != minimap_settings.minimap_enabled()
19853                {
19854                    self.set_minimap_visibility(
19855                        MinimapVisibility::for_mode(self.mode(), cx),
19856                        window,
19857                        cx,
19858                    );
19859                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19860                    minimap_entity.update(cx, |minimap_editor, cx| {
19861                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19862                    })
19863                }
19864            }
19865        }
19866
19867        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19868            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19869        }) {
19870            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19871                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19872            }
19873            self.refresh_colors(false, None, window, cx);
19874        }
19875
19876        cx.notify();
19877    }
19878
19879    pub fn set_searchable(&mut self, searchable: bool) {
19880        self.searchable = searchable;
19881    }
19882
19883    pub fn searchable(&self) -> bool {
19884        self.searchable
19885    }
19886
19887    fn open_proposed_changes_editor(
19888        &mut self,
19889        _: &OpenProposedChangesEditor,
19890        window: &mut Window,
19891        cx: &mut Context<Self>,
19892    ) {
19893        let Some(workspace) = self.workspace() else {
19894            cx.propagate();
19895            return;
19896        };
19897
19898        let selections = self.selections.all::<usize>(cx);
19899        let multi_buffer = self.buffer.read(cx);
19900        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19901        let mut new_selections_by_buffer = HashMap::default();
19902        for selection in selections {
19903            for (buffer, range, _) in
19904                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19905            {
19906                let mut range = range.to_point(buffer);
19907                range.start.column = 0;
19908                range.end.column = buffer.line_len(range.end.row);
19909                new_selections_by_buffer
19910                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19911                    .or_insert(Vec::new())
19912                    .push(range)
19913            }
19914        }
19915
19916        let proposed_changes_buffers = new_selections_by_buffer
19917            .into_iter()
19918            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19919            .collect::<Vec<_>>();
19920        let proposed_changes_editor = cx.new(|cx| {
19921            ProposedChangesEditor::new(
19922                "Proposed changes",
19923                proposed_changes_buffers,
19924                self.project.clone(),
19925                window,
19926                cx,
19927            )
19928        });
19929
19930        window.defer(cx, move |window, cx| {
19931            workspace.update(cx, |workspace, cx| {
19932                workspace.active_pane().update(cx, |pane, cx| {
19933                    pane.add_item(
19934                        Box::new(proposed_changes_editor),
19935                        true,
19936                        true,
19937                        None,
19938                        window,
19939                        cx,
19940                    );
19941                });
19942            });
19943        });
19944    }
19945
19946    pub fn open_excerpts_in_split(
19947        &mut self,
19948        _: &OpenExcerptsSplit,
19949        window: &mut Window,
19950        cx: &mut Context<Self>,
19951    ) {
19952        self.open_excerpts_common(None, true, window, cx)
19953    }
19954
19955    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19956        self.open_excerpts_common(None, false, window, cx)
19957    }
19958
19959    fn open_excerpts_common(
19960        &mut self,
19961        jump_data: Option<JumpData>,
19962        split: bool,
19963        window: &mut Window,
19964        cx: &mut Context<Self>,
19965    ) {
19966        let Some(workspace) = self.workspace() else {
19967            cx.propagate();
19968            return;
19969        };
19970
19971        if self.buffer.read(cx).is_singleton() {
19972            cx.propagate();
19973            return;
19974        }
19975
19976        let mut new_selections_by_buffer = HashMap::default();
19977        match &jump_data {
19978            Some(JumpData::MultiBufferPoint {
19979                excerpt_id,
19980                position,
19981                anchor,
19982                line_offset_from_top,
19983            }) => {
19984                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19985                if let Some(buffer) = multi_buffer_snapshot
19986                    .buffer_id_for_excerpt(*excerpt_id)
19987                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19988                {
19989                    let buffer_snapshot = buffer.read(cx).snapshot();
19990                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19991                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19992                    } else {
19993                        buffer_snapshot.clip_point(*position, Bias::Left)
19994                    };
19995                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19996                    new_selections_by_buffer.insert(
19997                        buffer,
19998                        (
19999                            vec![jump_to_offset..jump_to_offset],
20000                            Some(*line_offset_from_top),
20001                        ),
20002                    );
20003                }
20004            }
20005            Some(JumpData::MultiBufferRow {
20006                row,
20007                line_offset_from_top,
20008            }) => {
20009                let point = MultiBufferPoint::new(row.0, 0);
20010                if let Some((buffer, buffer_point, _)) =
20011                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20012                {
20013                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20014                    new_selections_by_buffer
20015                        .entry(buffer)
20016                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20017                        .0
20018                        .push(buffer_offset..buffer_offset)
20019                }
20020            }
20021            None => {
20022                let selections = self.selections.all::<usize>(cx);
20023                let multi_buffer = self.buffer.read(cx);
20024                for selection in selections {
20025                    for (snapshot, range, _, anchor) in multi_buffer
20026                        .snapshot(cx)
20027                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20028                    {
20029                        if let Some(anchor) = anchor {
20030                            // selection is in a deleted hunk
20031                            let Some(buffer_id) = anchor.buffer_id else {
20032                                continue;
20033                            };
20034                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20035                                continue;
20036                            };
20037                            let offset = text::ToOffset::to_offset(
20038                                &anchor.text_anchor,
20039                                &buffer_handle.read(cx).snapshot(),
20040                            );
20041                            let range = offset..offset;
20042                            new_selections_by_buffer
20043                                .entry(buffer_handle)
20044                                .or_insert((Vec::new(), None))
20045                                .0
20046                                .push(range)
20047                        } else {
20048                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20049                            else {
20050                                continue;
20051                            };
20052                            new_selections_by_buffer
20053                                .entry(buffer_handle)
20054                                .or_insert((Vec::new(), None))
20055                                .0
20056                                .push(range)
20057                        }
20058                    }
20059                }
20060            }
20061        }
20062
20063        new_selections_by_buffer
20064            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20065
20066        if new_selections_by_buffer.is_empty() {
20067            return;
20068        }
20069
20070        // We defer the pane interaction because we ourselves are a workspace item
20071        // and activating a new item causes the pane to call a method on us reentrantly,
20072        // which panics if we're on the stack.
20073        window.defer(cx, move |window, cx| {
20074            workspace.update(cx, |workspace, cx| {
20075                let pane = if split {
20076                    workspace.adjacent_pane(window, cx)
20077                } else {
20078                    workspace.active_pane().clone()
20079                };
20080
20081                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20082                    let editor = buffer
20083                        .read(cx)
20084                        .file()
20085                        .is_none()
20086                        .then(|| {
20087                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20088                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20089                            // Instead, we try to activate the existing editor in the pane first.
20090                            let (editor, pane_item_index) =
20091                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20092                                    let editor = item.downcast::<Editor>()?;
20093                                    let singleton_buffer =
20094                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20095                                    if singleton_buffer == buffer {
20096                                        Some((editor, i))
20097                                    } else {
20098                                        None
20099                                    }
20100                                })?;
20101                            pane.update(cx, |pane, cx| {
20102                                pane.activate_item(pane_item_index, true, true, window, cx)
20103                            });
20104                            Some(editor)
20105                        })
20106                        .flatten()
20107                        .unwrap_or_else(|| {
20108                            workspace.open_project_item::<Self>(
20109                                pane.clone(),
20110                                buffer,
20111                                true,
20112                                true,
20113                                window,
20114                                cx,
20115                            )
20116                        });
20117
20118                    editor.update(cx, |editor, cx| {
20119                        let autoscroll = match scroll_offset {
20120                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20121                            None => Autoscroll::newest(),
20122                        };
20123                        let nav_history = editor.nav_history.take();
20124                        editor.change_selections(
20125                            SelectionEffects::scroll(autoscroll),
20126                            window,
20127                            cx,
20128                            |s| {
20129                                s.select_ranges(ranges);
20130                            },
20131                        );
20132                        editor.nav_history = nav_history;
20133                    });
20134                }
20135            })
20136        });
20137    }
20138
20139    // For now, don't allow opening excerpts in buffers that aren't backed by
20140    // regular project files.
20141    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20142        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20143    }
20144
20145    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20146        let snapshot = self.buffer.read(cx).read(cx);
20147        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20148        Some(
20149            ranges
20150                .iter()
20151                .map(move |range| {
20152                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20153                })
20154                .collect(),
20155        )
20156    }
20157
20158    fn selection_replacement_ranges(
20159        &self,
20160        range: Range<OffsetUtf16>,
20161        cx: &mut App,
20162    ) -> Vec<Range<OffsetUtf16>> {
20163        let selections = self.selections.all::<OffsetUtf16>(cx);
20164        let newest_selection = selections
20165            .iter()
20166            .max_by_key(|selection| selection.id)
20167            .unwrap();
20168        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20169        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20170        let snapshot = self.buffer.read(cx).read(cx);
20171        selections
20172            .into_iter()
20173            .map(|mut selection| {
20174                selection.start.0 =
20175                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20176                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20177                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20178                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20179            })
20180            .collect()
20181    }
20182
20183    fn report_editor_event(
20184        &self,
20185        event_type: &'static str,
20186        file_extension: Option<String>,
20187        cx: &App,
20188    ) {
20189        if cfg!(any(test, feature = "test-support")) {
20190            return;
20191        }
20192
20193        let Some(project) = &self.project else { return };
20194
20195        // If None, we are in a file without an extension
20196        let file = self
20197            .buffer
20198            .read(cx)
20199            .as_singleton()
20200            .and_then(|b| b.read(cx).file());
20201        let file_extension = file_extension.or(file
20202            .as_ref()
20203            .and_then(|file| Path::new(file.file_name(cx)).extension())
20204            .and_then(|e| e.to_str())
20205            .map(|a| a.to_string()));
20206
20207        let vim_mode = vim_enabled(cx);
20208
20209        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20210        let copilot_enabled = edit_predictions_provider
20211            == language::language_settings::EditPredictionProvider::Copilot;
20212        let copilot_enabled_for_language = self
20213            .buffer
20214            .read(cx)
20215            .language_settings(cx)
20216            .show_edit_predictions;
20217
20218        let project = project.read(cx);
20219        telemetry::event!(
20220            event_type,
20221            file_extension,
20222            vim_mode,
20223            copilot_enabled,
20224            copilot_enabled_for_language,
20225            edit_predictions_provider,
20226            is_via_ssh = project.is_via_ssh(),
20227        );
20228    }
20229
20230    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20231    /// with each line being an array of {text, highlight} objects.
20232    fn copy_highlight_json(
20233        &mut self,
20234        _: &CopyHighlightJson,
20235        window: &mut Window,
20236        cx: &mut Context<Self>,
20237    ) {
20238        #[derive(Serialize)]
20239        struct Chunk<'a> {
20240            text: String,
20241            highlight: Option<&'a str>,
20242        }
20243
20244        let snapshot = self.buffer.read(cx).snapshot(cx);
20245        let range = self
20246            .selected_text_range(false, window, cx)
20247            .and_then(|selection| {
20248                if selection.range.is_empty() {
20249                    None
20250                } else {
20251                    Some(selection.range)
20252                }
20253            })
20254            .unwrap_or_else(|| 0..snapshot.len());
20255
20256        let chunks = snapshot.chunks(range, true);
20257        let mut lines = Vec::new();
20258        let mut line: VecDeque<Chunk> = VecDeque::new();
20259
20260        let Some(style) = self.style.as_ref() else {
20261            return;
20262        };
20263
20264        for chunk in chunks {
20265            let highlight = chunk
20266                .syntax_highlight_id
20267                .and_then(|id| id.name(&style.syntax));
20268            let mut chunk_lines = chunk.text.split('\n').peekable();
20269            while let Some(text) = chunk_lines.next() {
20270                let mut merged_with_last_token = false;
20271                if let Some(last_token) = line.back_mut() {
20272                    if last_token.highlight == highlight {
20273                        last_token.text.push_str(text);
20274                        merged_with_last_token = true;
20275                    }
20276                }
20277
20278                if !merged_with_last_token {
20279                    line.push_back(Chunk {
20280                        text: text.into(),
20281                        highlight,
20282                    });
20283                }
20284
20285                if chunk_lines.peek().is_some() {
20286                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20287                        line.pop_front();
20288                    }
20289                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20290                        line.pop_back();
20291                    }
20292
20293                    lines.push(mem::take(&mut line));
20294                }
20295            }
20296        }
20297
20298        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20299            return;
20300        };
20301        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20302    }
20303
20304    pub fn open_context_menu(
20305        &mut self,
20306        _: &OpenContextMenu,
20307        window: &mut Window,
20308        cx: &mut Context<Self>,
20309    ) {
20310        self.request_autoscroll(Autoscroll::newest(), cx);
20311        let position = self.selections.newest_display(cx).start;
20312        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20313    }
20314
20315    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20316        &self.inlay_hint_cache
20317    }
20318
20319    pub fn replay_insert_event(
20320        &mut self,
20321        text: &str,
20322        relative_utf16_range: Option<Range<isize>>,
20323        window: &mut Window,
20324        cx: &mut Context<Self>,
20325    ) {
20326        if !self.input_enabled {
20327            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20328            return;
20329        }
20330        if let Some(relative_utf16_range) = relative_utf16_range {
20331            let selections = self.selections.all::<OffsetUtf16>(cx);
20332            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20333                let new_ranges = selections.into_iter().map(|range| {
20334                    let start = OffsetUtf16(
20335                        range
20336                            .head()
20337                            .0
20338                            .saturating_add_signed(relative_utf16_range.start),
20339                    );
20340                    let end = OffsetUtf16(
20341                        range
20342                            .head()
20343                            .0
20344                            .saturating_add_signed(relative_utf16_range.end),
20345                    );
20346                    start..end
20347                });
20348                s.select_ranges(new_ranges);
20349            });
20350        }
20351
20352        self.handle_input(text, window, cx);
20353    }
20354
20355    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20356        let Some(provider) = self.semantics_provider.as_ref() else {
20357            return false;
20358        };
20359
20360        let mut supports = false;
20361        self.buffer().update(cx, |this, cx| {
20362            this.for_each_buffer(|buffer| {
20363                supports |= provider.supports_inlay_hints(buffer, cx);
20364            });
20365        });
20366
20367        supports
20368    }
20369
20370    pub fn is_focused(&self, window: &Window) -> bool {
20371        self.focus_handle.is_focused(window)
20372    }
20373
20374    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20375        cx.emit(EditorEvent::Focused);
20376
20377        if let Some(descendant) = self
20378            .last_focused_descendant
20379            .take()
20380            .and_then(|descendant| descendant.upgrade())
20381        {
20382            window.focus(&descendant);
20383        } else {
20384            if let Some(blame) = self.blame.as_ref() {
20385                blame.update(cx, GitBlame::focus)
20386            }
20387
20388            self.blink_manager.update(cx, BlinkManager::enable);
20389            self.show_cursor_names(window, cx);
20390            self.buffer.update(cx, |buffer, cx| {
20391                buffer.finalize_last_transaction(cx);
20392                if self.leader_id.is_none() {
20393                    buffer.set_active_selections(
20394                        &self.selections.disjoint_anchors(),
20395                        self.selections.line_mode,
20396                        self.cursor_shape,
20397                        cx,
20398                    );
20399                }
20400            });
20401        }
20402    }
20403
20404    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20405        cx.emit(EditorEvent::FocusedIn)
20406    }
20407
20408    fn handle_focus_out(
20409        &mut self,
20410        event: FocusOutEvent,
20411        _window: &mut Window,
20412        cx: &mut Context<Self>,
20413    ) {
20414        if event.blurred != self.focus_handle {
20415            self.last_focused_descendant = Some(event.blurred);
20416        }
20417        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20418    }
20419
20420    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20421        self.blink_manager.update(cx, BlinkManager::disable);
20422        self.buffer
20423            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20424
20425        if let Some(blame) = self.blame.as_ref() {
20426            blame.update(cx, GitBlame::blur)
20427        }
20428        if !self.hover_state.focused(window, cx) {
20429            hide_hover(self, cx);
20430        }
20431        if !self
20432            .context_menu
20433            .borrow()
20434            .as_ref()
20435            .is_some_and(|context_menu| context_menu.focused(window, cx))
20436        {
20437            self.hide_context_menu(window, cx);
20438        }
20439        self.discard_inline_completion(false, cx);
20440        cx.emit(EditorEvent::Blurred);
20441        cx.notify();
20442    }
20443
20444    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20445        let mut pending: String = window
20446            .pending_input_keystrokes()
20447            .into_iter()
20448            .flatten()
20449            .filter_map(|keystroke| {
20450                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20451                    keystroke.key_char.clone()
20452                } else {
20453                    None
20454                }
20455            })
20456            .collect();
20457
20458        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20459            pending = "".to_string();
20460        }
20461
20462        let existing_pending = self
20463            .text_highlights::<PendingInput>(cx)
20464            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20465        if existing_pending.is_none() && pending.is_empty() {
20466            return;
20467        }
20468        let transaction =
20469            self.transact(window, cx, |this, window, cx| {
20470                let selections = this.selections.all::<usize>(cx);
20471                let edits = selections
20472                    .iter()
20473                    .map(|selection| (selection.end..selection.end, pending.clone()));
20474                this.edit(edits, cx);
20475                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20476                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20477                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20478                    }));
20479                });
20480                if let Some(existing_ranges) = existing_pending {
20481                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20482                    this.edit(edits, cx);
20483                }
20484            });
20485
20486        let snapshot = self.snapshot(window, cx);
20487        let ranges = self
20488            .selections
20489            .all::<usize>(cx)
20490            .into_iter()
20491            .map(|selection| {
20492                snapshot.buffer_snapshot.anchor_after(selection.end)
20493                    ..snapshot
20494                        .buffer_snapshot
20495                        .anchor_before(selection.end + pending.len())
20496            })
20497            .collect();
20498
20499        if pending.is_empty() {
20500            self.clear_highlights::<PendingInput>(cx);
20501        } else {
20502            self.highlight_text::<PendingInput>(
20503                ranges,
20504                HighlightStyle {
20505                    underline: Some(UnderlineStyle {
20506                        thickness: px(1.),
20507                        color: None,
20508                        wavy: false,
20509                    }),
20510                    ..Default::default()
20511                },
20512                cx,
20513            );
20514        }
20515
20516        self.ime_transaction = self.ime_transaction.or(transaction);
20517        if let Some(transaction) = self.ime_transaction {
20518            self.buffer.update(cx, |buffer, cx| {
20519                buffer.group_until_transaction(transaction, cx);
20520            });
20521        }
20522
20523        if self.text_highlights::<PendingInput>(cx).is_none() {
20524            self.ime_transaction.take();
20525        }
20526    }
20527
20528    pub fn register_action_renderer(
20529        &mut self,
20530        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20531    ) -> Subscription {
20532        let id = self.next_editor_action_id.post_inc();
20533        self.editor_actions
20534            .borrow_mut()
20535            .insert(id, Box::new(listener));
20536
20537        let editor_actions = self.editor_actions.clone();
20538        Subscription::new(move || {
20539            editor_actions.borrow_mut().remove(&id);
20540        })
20541    }
20542
20543    pub fn register_action<A: Action>(
20544        &mut self,
20545        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20546    ) -> Subscription {
20547        let id = self.next_editor_action_id.post_inc();
20548        let listener = Arc::new(listener);
20549        self.editor_actions.borrow_mut().insert(
20550            id,
20551            Box::new(move |_, window, _| {
20552                let listener = listener.clone();
20553                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20554                    let action = action.downcast_ref().unwrap();
20555                    if phase == DispatchPhase::Bubble {
20556                        listener(action, window, cx)
20557                    }
20558                })
20559            }),
20560        );
20561
20562        let editor_actions = self.editor_actions.clone();
20563        Subscription::new(move || {
20564            editor_actions.borrow_mut().remove(&id);
20565        })
20566    }
20567
20568    pub fn file_header_size(&self) -> u32 {
20569        FILE_HEADER_HEIGHT
20570    }
20571
20572    pub fn restore(
20573        &mut self,
20574        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20575        window: &mut Window,
20576        cx: &mut Context<Self>,
20577    ) {
20578        let workspace = self.workspace();
20579        let project = self.project.as_ref();
20580        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20581            let mut tasks = Vec::new();
20582            for (buffer_id, changes) in revert_changes {
20583                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20584                    buffer.update(cx, |buffer, cx| {
20585                        buffer.edit(
20586                            changes
20587                                .into_iter()
20588                                .map(|(range, text)| (range, text.to_string())),
20589                            None,
20590                            cx,
20591                        );
20592                    });
20593
20594                    if let Some(project) =
20595                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20596                    {
20597                        project.update(cx, |project, cx| {
20598                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20599                        })
20600                    }
20601                }
20602            }
20603            tasks
20604        });
20605        cx.spawn_in(window, async move |_, cx| {
20606            for (buffer, task) in save_tasks {
20607                let result = task.await;
20608                if result.is_err() {
20609                    let Some(path) = buffer
20610                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20611                        .ok()
20612                    else {
20613                        continue;
20614                    };
20615                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20616                        let Some(task) = cx
20617                            .update_window_entity(&workspace, |workspace, window, cx| {
20618                                workspace
20619                                    .open_path_preview(path, None, false, false, false, window, cx)
20620                            })
20621                            .ok()
20622                        else {
20623                            continue;
20624                        };
20625                        task.await.log_err();
20626                    }
20627                }
20628            }
20629        })
20630        .detach();
20631        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20632            selections.refresh()
20633        });
20634    }
20635
20636    pub fn to_pixel_point(
20637        &self,
20638        source: multi_buffer::Anchor,
20639        editor_snapshot: &EditorSnapshot,
20640        window: &mut Window,
20641    ) -> Option<gpui::Point<Pixels>> {
20642        let source_point = source.to_display_point(editor_snapshot);
20643        self.display_to_pixel_point(source_point, editor_snapshot, window)
20644    }
20645
20646    pub fn display_to_pixel_point(
20647        &self,
20648        source: DisplayPoint,
20649        editor_snapshot: &EditorSnapshot,
20650        window: &mut Window,
20651    ) -> Option<gpui::Point<Pixels>> {
20652        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20653        let text_layout_details = self.text_layout_details(window);
20654        let scroll_top = text_layout_details
20655            .scroll_anchor
20656            .scroll_position(editor_snapshot)
20657            .y;
20658
20659        if source.row().as_f32() < scroll_top.floor() {
20660            return None;
20661        }
20662        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20663        let source_y = line_height * (source.row().as_f32() - scroll_top);
20664        Some(gpui::Point::new(source_x, source_y))
20665    }
20666
20667    pub fn has_visible_completions_menu(&self) -> bool {
20668        !self.edit_prediction_preview_is_active()
20669            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20670                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20671            })
20672    }
20673
20674    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20675        if self.mode.is_minimap() {
20676            return;
20677        }
20678        self.addons
20679            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20680    }
20681
20682    pub fn unregister_addon<T: Addon>(&mut self) {
20683        self.addons.remove(&std::any::TypeId::of::<T>());
20684    }
20685
20686    pub fn addon<T: Addon>(&self) -> Option<&T> {
20687        let type_id = std::any::TypeId::of::<T>();
20688        self.addons
20689            .get(&type_id)
20690            .and_then(|item| item.to_any().downcast_ref::<T>())
20691    }
20692
20693    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20694        let type_id = std::any::TypeId::of::<T>();
20695        self.addons
20696            .get_mut(&type_id)
20697            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20698    }
20699
20700    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20701        let text_layout_details = self.text_layout_details(window);
20702        let style = &text_layout_details.editor_style;
20703        let font_id = window.text_system().resolve_font(&style.text.font());
20704        let font_size = style.text.font_size.to_pixels(window.rem_size());
20705        let line_height = style.text.line_height_in_pixels(window.rem_size());
20706        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20707        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20708
20709        CharacterDimensions {
20710            em_width,
20711            em_advance,
20712            line_height,
20713        }
20714    }
20715
20716    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20717        self.load_diff_task.clone()
20718    }
20719
20720    fn read_metadata_from_db(
20721        &mut self,
20722        item_id: u64,
20723        workspace_id: WorkspaceId,
20724        window: &mut Window,
20725        cx: &mut Context<Editor>,
20726    ) {
20727        if self.is_singleton(cx)
20728            && !self.mode.is_minimap()
20729            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20730        {
20731            let buffer_snapshot = OnceCell::new();
20732
20733            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20734                if !folds.is_empty() {
20735                    let snapshot =
20736                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20737                    self.fold_ranges(
20738                        folds
20739                            .into_iter()
20740                            .map(|(start, end)| {
20741                                snapshot.clip_offset(start, Bias::Left)
20742                                    ..snapshot.clip_offset(end, Bias::Right)
20743                            })
20744                            .collect(),
20745                        false,
20746                        window,
20747                        cx,
20748                    );
20749                }
20750            }
20751
20752            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20753                if !selections.is_empty() {
20754                    let snapshot =
20755                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20756                    // skip adding the initial selection to selection history
20757                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20758                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20759                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20760                            snapshot.clip_offset(start, Bias::Left)
20761                                ..snapshot.clip_offset(end, Bias::Right)
20762                        }));
20763                    });
20764                    self.selection_history.mode = SelectionHistoryMode::Normal;
20765                }
20766            };
20767        }
20768
20769        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20770    }
20771
20772    fn update_lsp_data(
20773        &mut self,
20774        ignore_cache: bool,
20775        for_buffer: Option<BufferId>,
20776        window: &mut Window,
20777        cx: &mut Context<'_, Self>,
20778    ) {
20779        self.pull_diagnostics(for_buffer, window, cx);
20780        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20781    }
20782}
20783
20784fn vim_enabled(cx: &App) -> bool {
20785    cx.global::<SettingsStore>()
20786        .raw_user_settings()
20787        .get("vim_mode")
20788        == Some(&serde_json::Value::Bool(true))
20789}
20790
20791fn process_completion_for_edit(
20792    completion: &Completion,
20793    intent: CompletionIntent,
20794    buffer: &Entity<Buffer>,
20795    cursor_position: &text::Anchor,
20796    cx: &mut Context<Editor>,
20797) -> CompletionEdit {
20798    let buffer = buffer.read(cx);
20799    let buffer_snapshot = buffer.snapshot();
20800    let (snippet, new_text) = if completion.is_snippet() {
20801        // Workaround for typescript language server issues so that methods don't expand within
20802        // strings and functions with type expressions. The previous point is used because the query
20803        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20804        let mut snippet_source = completion.new_text.clone();
20805        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20806        previous_point.column = previous_point.column.saturating_sub(1);
20807        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20808            if scope.prefers_label_for_snippet_in_completion() {
20809                if let Some(label) = completion.label() {
20810                    if matches!(
20811                        completion.kind(),
20812                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20813                    ) {
20814                        snippet_source = label;
20815                    }
20816                }
20817            }
20818        }
20819        match Snippet::parse(&snippet_source).log_err() {
20820            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20821            None => (None, completion.new_text.clone()),
20822        }
20823    } else {
20824        (None, completion.new_text.clone())
20825    };
20826
20827    let mut range_to_replace = {
20828        let replace_range = &completion.replace_range;
20829        if let CompletionSource::Lsp {
20830            insert_range: Some(insert_range),
20831            ..
20832        } = &completion.source
20833        {
20834            debug_assert_eq!(
20835                insert_range.start, replace_range.start,
20836                "insert_range and replace_range should start at the same position"
20837            );
20838            debug_assert!(
20839                insert_range
20840                    .start
20841                    .cmp(&cursor_position, &buffer_snapshot)
20842                    .is_le(),
20843                "insert_range should start before or at cursor position"
20844            );
20845            debug_assert!(
20846                replace_range
20847                    .start
20848                    .cmp(&cursor_position, &buffer_snapshot)
20849                    .is_le(),
20850                "replace_range should start before or at cursor position"
20851            );
20852            debug_assert!(
20853                insert_range
20854                    .end
20855                    .cmp(&cursor_position, &buffer_snapshot)
20856                    .is_le(),
20857                "insert_range should end before or at cursor position"
20858            );
20859
20860            let should_replace = match intent {
20861                CompletionIntent::CompleteWithInsert => false,
20862                CompletionIntent::CompleteWithReplace => true,
20863                CompletionIntent::Complete | CompletionIntent::Compose => {
20864                    let insert_mode =
20865                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20866                            .completions
20867                            .lsp_insert_mode;
20868                    match insert_mode {
20869                        LspInsertMode::Insert => false,
20870                        LspInsertMode::Replace => true,
20871                        LspInsertMode::ReplaceSubsequence => {
20872                            let mut text_to_replace = buffer.chars_for_range(
20873                                buffer.anchor_before(replace_range.start)
20874                                    ..buffer.anchor_after(replace_range.end),
20875                            );
20876                            let mut current_needle = text_to_replace.next();
20877                            for haystack_ch in completion.label.text.chars() {
20878                                if let Some(needle_ch) = current_needle {
20879                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20880                                        current_needle = text_to_replace.next();
20881                                    }
20882                                }
20883                            }
20884                            current_needle.is_none()
20885                        }
20886                        LspInsertMode::ReplaceSuffix => {
20887                            if replace_range
20888                                .end
20889                                .cmp(&cursor_position, &buffer_snapshot)
20890                                .is_gt()
20891                            {
20892                                let range_after_cursor = *cursor_position..replace_range.end;
20893                                let text_after_cursor = buffer
20894                                    .text_for_range(
20895                                        buffer.anchor_before(range_after_cursor.start)
20896                                            ..buffer.anchor_after(range_after_cursor.end),
20897                                    )
20898                                    .collect::<String>()
20899                                    .to_ascii_lowercase();
20900                                completion
20901                                    .label
20902                                    .text
20903                                    .to_ascii_lowercase()
20904                                    .ends_with(&text_after_cursor)
20905                            } else {
20906                                true
20907                            }
20908                        }
20909                    }
20910                }
20911            };
20912
20913            if should_replace {
20914                replace_range.clone()
20915            } else {
20916                insert_range.clone()
20917            }
20918        } else {
20919            replace_range.clone()
20920        }
20921    };
20922
20923    if range_to_replace
20924        .end
20925        .cmp(&cursor_position, &buffer_snapshot)
20926        .is_lt()
20927    {
20928        range_to_replace.end = *cursor_position;
20929    }
20930
20931    CompletionEdit {
20932        new_text,
20933        replace_range: range_to_replace.to_offset(&buffer),
20934        snippet,
20935    }
20936}
20937
20938struct CompletionEdit {
20939    new_text: String,
20940    replace_range: Range<usize>,
20941    snippet: Option<Snippet>,
20942}
20943
20944fn insert_extra_newline_brackets(
20945    buffer: &MultiBufferSnapshot,
20946    range: Range<usize>,
20947    language: &language::LanguageScope,
20948) -> bool {
20949    let leading_whitespace_len = buffer
20950        .reversed_chars_at(range.start)
20951        .take_while(|c| c.is_whitespace() && *c != '\n')
20952        .map(|c| c.len_utf8())
20953        .sum::<usize>();
20954    let trailing_whitespace_len = buffer
20955        .chars_at(range.end)
20956        .take_while(|c| c.is_whitespace() && *c != '\n')
20957        .map(|c| c.len_utf8())
20958        .sum::<usize>();
20959    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20960
20961    language.brackets().any(|(pair, enabled)| {
20962        let pair_start = pair.start.trim_end();
20963        let pair_end = pair.end.trim_start();
20964
20965        enabled
20966            && pair.newline
20967            && buffer.contains_str_at(range.end, pair_end)
20968            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20969    })
20970}
20971
20972fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20973    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20974        [(buffer, range, _)] => (*buffer, range.clone()),
20975        _ => return false,
20976    };
20977    let pair = {
20978        let mut result: Option<BracketMatch> = None;
20979
20980        for pair in buffer
20981            .all_bracket_ranges(range.clone())
20982            .filter(move |pair| {
20983                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20984            })
20985        {
20986            let len = pair.close_range.end - pair.open_range.start;
20987
20988            if let Some(existing) = &result {
20989                let existing_len = existing.close_range.end - existing.open_range.start;
20990                if len > existing_len {
20991                    continue;
20992                }
20993            }
20994
20995            result = Some(pair);
20996        }
20997
20998        result
20999    };
21000    let Some(pair) = pair else {
21001        return false;
21002    };
21003    pair.newline_only
21004        && buffer
21005            .chars_for_range(pair.open_range.end..range.start)
21006            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21007            .all(|c| c.is_whitespace() && c != '\n')
21008}
21009
21010fn update_uncommitted_diff_for_buffer(
21011    editor: Entity<Editor>,
21012    project: &Entity<Project>,
21013    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21014    buffer: Entity<MultiBuffer>,
21015    cx: &mut App,
21016) -> Task<()> {
21017    let mut tasks = Vec::new();
21018    project.update(cx, |project, cx| {
21019        for buffer in buffers {
21020            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21021                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21022            }
21023        }
21024    });
21025    cx.spawn(async move |cx| {
21026        let diffs = future::join_all(tasks).await;
21027        if editor
21028            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21029            .unwrap_or(false)
21030        {
21031            return;
21032        }
21033
21034        buffer
21035            .update(cx, |buffer, cx| {
21036                for diff in diffs.into_iter().flatten() {
21037                    buffer.add_diff(diff, cx);
21038                }
21039            })
21040            .ok();
21041    })
21042}
21043
21044fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21045    let tab_size = tab_size.get() as usize;
21046    let mut width = offset;
21047
21048    for ch in text.chars() {
21049        width += if ch == '\t' {
21050            tab_size - (width % tab_size)
21051        } else {
21052            1
21053        };
21054    }
21055
21056    width - offset
21057}
21058
21059#[cfg(test)]
21060mod tests {
21061    use super::*;
21062
21063    #[test]
21064    fn test_string_size_with_expanded_tabs() {
21065        let nz = |val| NonZeroU32::new(val).unwrap();
21066        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21067        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21068        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21069        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21070        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21071        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21072        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21073        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21074    }
21075}
21076
21077/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21078struct WordBreakingTokenizer<'a> {
21079    input: &'a str,
21080}
21081
21082impl<'a> WordBreakingTokenizer<'a> {
21083    fn new(input: &'a str) -> Self {
21084        Self { input }
21085    }
21086}
21087
21088fn is_char_ideographic(ch: char) -> bool {
21089    use unicode_script::Script::*;
21090    use unicode_script::UnicodeScript;
21091    matches!(ch.script(), Han | Tangut | Yi)
21092}
21093
21094fn is_grapheme_ideographic(text: &str) -> bool {
21095    text.chars().any(is_char_ideographic)
21096}
21097
21098fn is_grapheme_whitespace(text: &str) -> bool {
21099    text.chars().any(|x| x.is_whitespace())
21100}
21101
21102fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21103    text.chars().next().map_or(false, |ch| {
21104        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21105    })
21106}
21107
21108#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21109enum WordBreakToken<'a> {
21110    Word { token: &'a str, grapheme_len: usize },
21111    InlineWhitespace { token: &'a str, grapheme_len: usize },
21112    Newline,
21113}
21114
21115impl<'a> Iterator for WordBreakingTokenizer<'a> {
21116    /// Yields a span, the count of graphemes in the token, and whether it was
21117    /// whitespace. Note that it also breaks at word boundaries.
21118    type Item = WordBreakToken<'a>;
21119
21120    fn next(&mut self) -> Option<Self::Item> {
21121        use unicode_segmentation::UnicodeSegmentation;
21122        if self.input.is_empty() {
21123            return None;
21124        }
21125
21126        let mut iter = self.input.graphemes(true).peekable();
21127        let mut offset = 0;
21128        let mut grapheme_len = 0;
21129        if let Some(first_grapheme) = iter.next() {
21130            let is_newline = first_grapheme == "\n";
21131            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21132            offset += first_grapheme.len();
21133            grapheme_len += 1;
21134            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21135                if let Some(grapheme) = iter.peek().copied() {
21136                    if should_stay_with_preceding_ideograph(grapheme) {
21137                        offset += grapheme.len();
21138                        grapheme_len += 1;
21139                    }
21140                }
21141            } else {
21142                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21143                let mut next_word_bound = words.peek().copied();
21144                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21145                    next_word_bound = words.next();
21146                }
21147                while let Some(grapheme) = iter.peek().copied() {
21148                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21149                        break;
21150                    };
21151                    if is_grapheme_whitespace(grapheme) != is_whitespace
21152                        || (grapheme == "\n") != is_newline
21153                    {
21154                        break;
21155                    };
21156                    offset += grapheme.len();
21157                    grapheme_len += 1;
21158                    iter.next();
21159                }
21160            }
21161            let token = &self.input[..offset];
21162            self.input = &self.input[offset..];
21163            if token == "\n" {
21164                Some(WordBreakToken::Newline)
21165            } else if is_whitespace {
21166                Some(WordBreakToken::InlineWhitespace {
21167                    token,
21168                    grapheme_len,
21169                })
21170            } else {
21171                Some(WordBreakToken::Word {
21172                    token,
21173                    grapheme_len,
21174                })
21175            }
21176        } else {
21177            None
21178        }
21179    }
21180}
21181
21182#[test]
21183fn test_word_breaking_tokenizer() {
21184    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21185        ("", &[]),
21186        ("  ", &[whitespace("  ", 2)]),
21187        ("Ʒ", &[word("Ʒ", 1)]),
21188        ("Ǽ", &[word("Ǽ", 1)]),
21189        ("", &[word("", 1)]),
21190        ("⋑⋑", &[word("⋑⋑", 2)]),
21191        (
21192            "原理,进而",
21193            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21194        ),
21195        (
21196            "hello world",
21197            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21198        ),
21199        (
21200            "hello, world",
21201            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21202        ),
21203        (
21204            "  hello world",
21205            &[
21206                whitespace("  ", 2),
21207                word("hello", 5),
21208                whitespace(" ", 1),
21209                word("world", 5),
21210            ],
21211        ),
21212        (
21213            "这是什么 \n 钢笔",
21214            &[
21215                word("", 1),
21216                word("", 1),
21217                word("", 1),
21218                word("", 1),
21219                whitespace(" ", 1),
21220                newline(),
21221                whitespace(" ", 1),
21222                word("", 1),
21223                word("", 1),
21224            ],
21225        ),
21226        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21227    ];
21228
21229    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21230        WordBreakToken::Word {
21231            token,
21232            grapheme_len,
21233        }
21234    }
21235
21236    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21237        WordBreakToken::InlineWhitespace {
21238            token,
21239            grapheme_len,
21240        }
21241    }
21242
21243    fn newline() -> WordBreakToken<'static> {
21244        WordBreakToken::Newline
21245    }
21246
21247    for (input, result) in tests {
21248        assert_eq!(
21249            WordBreakingTokenizer::new(input)
21250                .collect::<Vec<_>>()
21251                .as_slice(),
21252            *result,
21253        );
21254    }
21255}
21256
21257fn wrap_with_prefix(
21258    first_line_prefix: String,
21259    subsequent_lines_prefix: String,
21260    unwrapped_text: String,
21261    wrap_column: usize,
21262    tab_size: NonZeroU32,
21263    preserve_existing_whitespace: bool,
21264) -> String {
21265    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21266    let subsequent_lines_prefix_len =
21267        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21268    let mut wrapped_text = String::new();
21269    let mut current_line = first_line_prefix.clone();
21270    let mut is_first_line = true;
21271
21272    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21273    let mut current_line_len = first_line_prefix_len;
21274    let mut in_whitespace = false;
21275    for token in tokenizer {
21276        let have_preceding_whitespace = in_whitespace;
21277        match token {
21278            WordBreakToken::Word {
21279                token,
21280                grapheme_len,
21281            } => {
21282                in_whitespace = false;
21283                let current_prefix_len = if is_first_line {
21284                    first_line_prefix_len
21285                } else {
21286                    subsequent_lines_prefix_len
21287                };
21288                if current_line_len + grapheme_len > wrap_column
21289                    && current_line_len != current_prefix_len
21290                {
21291                    wrapped_text.push_str(current_line.trim_end());
21292                    wrapped_text.push('\n');
21293                    is_first_line = false;
21294                    current_line = subsequent_lines_prefix.clone();
21295                    current_line_len = subsequent_lines_prefix_len;
21296                }
21297                current_line.push_str(token);
21298                current_line_len += grapheme_len;
21299            }
21300            WordBreakToken::InlineWhitespace {
21301                mut token,
21302                mut grapheme_len,
21303            } => {
21304                in_whitespace = true;
21305                if have_preceding_whitespace && !preserve_existing_whitespace {
21306                    continue;
21307                }
21308                if !preserve_existing_whitespace {
21309                    token = " ";
21310                    grapheme_len = 1;
21311                }
21312                let current_prefix_len = if is_first_line {
21313                    first_line_prefix_len
21314                } else {
21315                    subsequent_lines_prefix_len
21316                };
21317                if current_line_len + grapheme_len > wrap_column {
21318                    wrapped_text.push_str(current_line.trim_end());
21319                    wrapped_text.push('\n');
21320                    is_first_line = false;
21321                    current_line = subsequent_lines_prefix.clone();
21322                    current_line_len = subsequent_lines_prefix_len;
21323                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21324                    current_line.push_str(token);
21325                    current_line_len += grapheme_len;
21326                }
21327            }
21328            WordBreakToken::Newline => {
21329                in_whitespace = true;
21330                let current_prefix_len = if is_first_line {
21331                    first_line_prefix_len
21332                } else {
21333                    subsequent_lines_prefix_len
21334                };
21335                if preserve_existing_whitespace {
21336                    wrapped_text.push_str(current_line.trim_end());
21337                    wrapped_text.push('\n');
21338                    is_first_line = false;
21339                    current_line = subsequent_lines_prefix.clone();
21340                    current_line_len = subsequent_lines_prefix_len;
21341                } else if have_preceding_whitespace {
21342                    continue;
21343                } else if current_line_len + 1 > wrap_column
21344                    && current_line_len != current_prefix_len
21345                {
21346                    wrapped_text.push_str(current_line.trim_end());
21347                    wrapped_text.push('\n');
21348                    is_first_line = false;
21349                    current_line = subsequent_lines_prefix.clone();
21350                    current_line_len = subsequent_lines_prefix_len;
21351                } else if current_line_len != current_prefix_len {
21352                    current_line.push(' ');
21353                    current_line_len += 1;
21354                }
21355            }
21356        }
21357    }
21358
21359    if !current_line.is_empty() {
21360        wrapped_text.push_str(&current_line);
21361    }
21362    wrapped_text
21363}
21364
21365#[test]
21366fn test_wrap_with_prefix() {
21367    assert_eq!(
21368        wrap_with_prefix(
21369            "# ".to_string(),
21370            "# ".to_string(),
21371            "abcdefg".to_string(),
21372            4,
21373            NonZeroU32::new(4).unwrap(),
21374            false,
21375        ),
21376        "# abcdefg"
21377    );
21378    assert_eq!(
21379        wrap_with_prefix(
21380            "".to_string(),
21381            "".to_string(),
21382            "\thello world".to_string(),
21383            8,
21384            NonZeroU32::new(4).unwrap(),
21385            false,
21386        ),
21387        "hello\nworld"
21388    );
21389    assert_eq!(
21390        wrap_with_prefix(
21391            "// ".to_string(),
21392            "// ".to_string(),
21393            "xx \nyy zz aa bb cc".to_string(),
21394            12,
21395            NonZeroU32::new(4).unwrap(),
21396            false,
21397        ),
21398        "// xx yy zz\n// aa bb cc"
21399    );
21400    assert_eq!(
21401        wrap_with_prefix(
21402            String::new(),
21403            String::new(),
21404            "这是什么 \n 钢笔".to_string(),
21405            3,
21406            NonZeroU32::new(4).unwrap(),
21407            false,
21408        ),
21409        "这是什\n么 钢\n"
21410    );
21411}
21412
21413pub trait CollaborationHub {
21414    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21415    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21416    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21417}
21418
21419impl CollaborationHub for Entity<Project> {
21420    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21421        self.read(cx).collaborators()
21422    }
21423
21424    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21425        self.read(cx).user_store().read(cx).participant_indices()
21426    }
21427
21428    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21429        let this = self.read(cx);
21430        let user_ids = this.collaborators().values().map(|c| c.user_id);
21431        this.user_store().read(cx).participant_names(user_ids, cx)
21432    }
21433}
21434
21435pub trait SemanticsProvider {
21436    fn hover(
21437        &self,
21438        buffer: &Entity<Buffer>,
21439        position: text::Anchor,
21440        cx: &mut App,
21441    ) -> Option<Task<Vec<project::Hover>>>;
21442
21443    fn inline_values(
21444        &self,
21445        buffer_handle: Entity<Buffer>,
21446        range: Range<text::Anchor>,
21447        cx: &mut App,
21448    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21449
21450    fn inlay_hints(
21451        &self,
21452        buffer_handle: Entity<Buffer>,
21453        range: Range<text::Anchor>,
21454        cx: &mut App,
21455    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21456
21457    fn resolve_inlay_hint(
21458        &self,
21459        hint: InlayHint,
21460        buffer_handle: Entity<Buffer>,
21461        server_id: LanguageServerId,
21462        cx: &mut App,
21463    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21464
21465    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21466
21467    fn document_highlights(
21468        &self,
21469        buffer: &Entity<Buffer>,
21470        position: text::Anchor,
21471        cx: &mut App,
21472    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21473
21474    fn definitions(
21475        &self,
21476        buffer: &Entity<Buffer>,
21477        position: text::Anchor,
21478        kind: GotoDefinitionKind,
21479        cx: &mut App,
21480    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21481
21482    fn range_for_rename(
21483        &self,
21484        buffer: &Entity<Buffer>,
21485        position: text::Anchor,
21486        cx: &mut App,
21487    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21488
21489    fn perform_rename(
21490        &self,
21491        buffer: &Entity<Buffer>,
21492        position: text::Anchor,
21493        new_name: String,
21494        cx: &mut App,
21495    ) -> Option<Task<Result<ProjectTransaction>>>;
21496}
21497
21498pub trait CompletionProvider {
21499    fn completions(
21500        &self,
21501        excerpt_id: ExcerptId,
21502        buffer: &Entity<Buffer>,
21503        buffer_position: text::Anchor,
21504        trigger: CompletionContext,
21505        window: &mut Window,
21506        cx: &mut Context<Editor>,
21507    ) -> Task<Result<Vec<CompletionResponse>>>;
21508
21509    fn resolve_completions(
21510        &self,
21511        _buffer: Entity<Buffer>,
21512        _completion_indices: Vec<usize>,
21513        _completions: Rc<RefCell<Box<[Completion]>>>,
21514        _cx: &mut Context<Editor>,
21515    ) -> Task<Result<bool>> {
21516        Task::ready(Ok(false))
21517    }
21518
21519    fn apply_additional_edits_for_completion(
21520        &self,
21521        _buffer: Entity<Buffer>,
21522        _completions: Rc<RefCell<Box<[Completion]>>>,
21523        _completion_index: usize,
21524        _push_to_history: bool,
21525        _cx: &mut Context<Editor>,
21526    ) -> Task<Result<Option<language::Transaction>>> {
21527        Task::ready(Ok(None))
21528    }
21529
21530    fn is_completion_trigger(
21531        &self,
21532        buffer: &Entity<Buffer>,
21533        position: language::Anchor,
21534        text: &str,
21535        trigger_in_words: bool,
21536        menu_is_open: bool,
21537        cx: &mut Context<Editor>,
21538    ) -> bool;
21539
21540    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21541
21542    fn sort_completions(&self) -> bool {
21543        true
21544    }
21545
21546    fn filter_completions(&self) -> bool {
21547        true
21548    }
21549}
21550
21551pub trait CodeActionProvider {
21552    fn id(&self) -> Arc<str>;
21553
21554    fn code_actions(
21555        &self,
21556        buffer: &Entity<Buffer>,
21557        range: Range<text::Anchor>,
21558        window: &mut Window,
21559        cx: &mut App,
21560    ) -> Task<Result<Vec<CodeAction>>>;
21561
21562    fn apply_code_action(
21563        &self,
21564        buffer_handle: Entity<Buffer>,
21565        action: CodeAction,
21566        excerpt_id: ExcerptId,
21567        push_to_history: bool,
21568        window: &mut Window,
21569        cx: &mut App,
21570    ) -> Task<Result<ProjectTransaction>>;
21571}
21572
21573impl CodeActionProvider for Entity<Project> {
21574    fn id(&self) -> Arc<str> {
21575        "project".into()
21576    }
21577
21578    fn code_actions(
21579        &self,
21580        buffer: &Entity<Buffer>,
21581        range: Range<text::Anchor>,
21582        _window: &mut Window,
21583        cx: &mut App,
21584    ) -> Task<Result<Vec<CodeAction>>> {
21585        self.update(cx, |project, cx| {
21586            let code_lens = project.code_lens(buffer, range.clone(), cx);
21587            let code_actions = project.code_actions(buffer, range, None, cx);
21588            cx.background_spawn(async move {
21589                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21590                Ok(code_lens
21591                    .context("code lens fetch")?
21592                    .into_iter()
21593                    .chain(code_actions.context("code action fetch")?)
21594                    .collect())
21595            })
21596        })
21597    }
21598
21599    fn apply_code_action(
21600        &self,
21601        buffer_handle: Entity<Buffer>,
21602        action: CodeAction,
21603        _excerpt_id: ExcerptId,
21604        push_to_history: bool,
21605        _window: &mut Window,
21606        cx: &mut App,
21607    ) -> Task<Result<ProjectTransaction>> {
21608        self.update(cx, |project, cx| {
21609            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21610        })
21611    }
21612}
21613
21614fn snippet_completions(
21615    project: &Project,
21616    buffer: &Entity<Buffer>,
21617    buffer_position: text::Anchor,
21618    cx: &mut App,
21619) -> Task<Result<CompletionResponse>> {
21620    let languages = buffer.read(cx).languages_at(buffer_position);
21621    let snippet_store = project.snippets().read(cx);
21622
21623    let scopes: Vec<_> = languages
21624        .iter()
21625        .filter_map(|language| {
21626            let language_name = language.lsp_id();
21627            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21628
21629            if snippets.is_empty() {
21630                None
21631            } else {
21632                Some((language.default_scope(), snippets))
21633            }
21634        })
21635        .collect();
21636
21637    if scopes.is_empty() {
21638        return Task::ready(Ok(CompletionResponse {
21639            completions: vec![],
21640            is_incomplete: false,
21641        }));
21642    }
21643
21644    let snapshot = buffer.read(cx).text_snapshot();
21645    let chars: String = snapshot
21646        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21647        .collect();
21648    let executor = cx.background_executor().clone();
21649
21650    cx.background_spawn(async move {
21651        let mut is_incomplete = false;
21652        let mut completions: Vec<Completion> = Vec::new();
21653        for (scope, snippets) in scopes.into_iter() {
21654            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21655            let mut last_word = chars
21656                .chars()
21657                .take_while(|c| classifier.is_word(*c))
21658                .collect::<String>();
21659            last_word = last_word.chars().rev().collect();
21660
21661            if last_word.is_empty() {
21662                return Ok(CompletionResponse {
21663                    completions: vec![],
21664                    is_incomplete: true,
21665                });
21666            }
21667
21668            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21669            let to_lsp = |point: &text::Anchor| {
21670                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21671                point_to_lsp(end)
21672            };
21673            let lsp_end = to_lsp(&buffer_position);
21674
21675            let candidates = snippets
21676                .iter()
21677                .enumerate()
21678                .flat_map(|(ix, snippet)| {
21679                    snippet
21680                        .prefix
21681                        .iter()
21682                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21683                })
21684                .collect::<Vec<StringMatchCandidate>>();
21685
21686            const MAX_RESULTS: usize = 100;
21687            let mut matches = fuzzy::match_strings(
21688                &candidates,
21689                &last_word,
21690                last_word.chars().any(|c| c.is_uppercase()),
21691                true,
21692                MAX_RESULTS,
21693                &Default::default(),
21694                executor.clone(),
21695            )
21696            .await;
21697
21698            if matches.len() >= MAX_RESULTS {
21699                is_incomplete = true;
21700            }
21701
21702            // Remove all candidates where the query's start does not match the start of any word in the candidate
21703            if let Some(query_start) = last_word.chars().next() {
21704                matches.retain(|string_match| {
21705                    split_words(&string_match.string).any(|word| {
21706                        // Check that the first codepoint of the word as lowercase matches the first
21707                        // codepoint of the query as lowercase
21708                        word.chars()
21709                            .flat_map(|codepoint| codepoint.to_lowercase())
21710                            .zip(query_start.to_lowercase())
21711                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21712                    })
21713                });
21714            }
21715
21716            let matched_strings = matches
21717                .into_iter()
21718                .map(|m| m.string)
21719                .collect::<HashSet<_>>();
21720
21721            completions.extend(snippets.iter().filter_map(|snippet| {
21722                let matching_prefix = snippet
21723                    .prefix
21724                    .iter()
21725                    .find(|prefix| matched_strings.contains(*prefix))?;
21726                let start = as_offset - last_word.len();
21727                let start = snapshot.anchor_before(start);
21728                let range = start..buffer_position;
21729                let lsp_start = to_lsp(&start);
21730                let lsp_range = lsp::Range {
21731                    start: lsp_start,
21732                    end: lsp_end,
21733                };
21734                Some(Completion {
21735                    replace_range: range,
21736                    new_text: snippet.body.clone(),
21737                    source: CompletionSource::Lsp {
21738                        insert_range: None,
21739                        server_id: LanguageServerId(usize::MAX),
21740                        resolved: true,
21741                        lsp_completion: Box::new(lsp::CompletionItem {
21742                            label: snippet.prefix.first().unwrap().clone(),
21743                            kind: Some(CompletionItemKind::SNIPPET),
21744                            label_details: snippet.description.as_ref().map(|description| {
21745                                lsp::CompletionItemLabelDetails {
21746                                    detail: Some(description.clone()),
21747                                    description: None,
21748                                }
21749                            }),
21750                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21751                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21752                                lsp::InsertReplaceEdit {
21753                                    new_text: snippet.body.clone(),
21754                                    insert: lsp_range,
21755                                    replace: lsp_range,
21756                                },
21757                            )),
21758                            filter_text: Some(snippet.body.clone()),
21759                            sort_text: Some(char::MAX.to_string()),
21760                            ..lsp::CompletionItem::default()
21761                        }),
21762                        lsp_defaults: None,
21763                    },
21764                    label: CodeLabel {
21765                        text: matching_prefix.clone(),
21766                        runs: Vec::new(),
21767                        filter_range: 0..matching_prefix.len(),
21768                    },
21769                    icon_path: None,
21770                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21771                        single_line: snippet.name.clone().into(),
21772                        plain_text: snippet
21773                            .description
21774                            .clone()
21775                            .map(|description| description.into()),
21776                    }),
21777                    insert_text_mode: None,
21778                    confirm: None,
21779                })
21780            }))
21781        }
21782
21783        Ok(CompletionResponse {
21784            completions,
21785            is_incomplete,
21786        })
21787    })
21788}
21789
21790impl CompletionProvider for Entity<Project> {
21791    fn completions(
21792        &self,
21793        _excerpt_id: ExcerptId,
21794        buffer: &Entity<Buffer>,
21795        buffer_position: text::Anchor,
21796        options: CompletionContext,
21797        _window: &mut Window,
21798        cx: &mut Context<Editor>,
21799    ) -> Task<Result<Vec<CompletionResponse>>> {
21800        self.update(cx, |project, cx| {
21801            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21802            let project_completions = project.completions(buffer, buffer_position, options, cx);
21803            cx.background_spawn(async move {
21804                let mut responses = project_completions.await?;
21805                let snippets = snippets.await?;
21806                if !snippets.completions.is_empty() {
21807                    responses.push(snippets);
21808                }
21809                Ok(responses)
21810            })
21811        })
21812    }
21813
21814    fn resolve_completions(
21815        &self,
21816        buffer: Entity<Buffer>,
21817        completion_indices: Vec<usize>,
21818        completions: Rc<RefCell<Box<[Completion]>>>,
21819        cx: &mut Context<Editor>,
21820    ) -> Task<Result<bool>> {
21821        self.update(cx, |project, cx| {
21822            project.lsp_store().update(cx, |lsp_store, cx| {
21823                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21824            })
21825        })
21826    }
21827
21828    fn apply_additional_edits_for_completion(
21829        &self,
21830        buffer: Entity<Buffer>,
21831        completions: Rc<RefCell<Box<[Completion]>>>,
21832        completion_index: usize,
21833        push_to_history: bool,
21834        cx: &mut Context<Editor>,
21835    ) -> Task<Result<Option<language::Transaction>>> {
21836        self.update(cx, |project, cx| {
21837            project.lsp_store().update(cx, |lsp_store, cx| {
21838                lsp_store.apply_additional_edits_for_completion(
21839                    buffer,
21840                    completions,
21841                    completion_index,
21842                    push_to_history,
21843                    cx,
21844                )
21845            })
21846        })
21847    }
21848
21849    fn is_completion_trigger(
21850        &self,
21851        buffer: &Entity<Buffer>,
21852        position: language::Anchor,
21853        text: &str,
21854        trigger_in_words: bool,
21855        menu_is_open: bool,
21856        cx: &mut Context<Editor>,
21857    ) -> bool {
21858        let mut chars = text.chars();
21859        let char = if let Some(char) = chars.next() {
21860            char
21861        } else {
21862            return false;
21863        };
21864        if chars.next().is_some() {
21865            return false;
21866        }
21867
21868        let buffer = buffer.read(cx);
21869        let snapshot = buffer.snapshot();
21870        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21871            return false;
21872        }
21873        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21874        if trigger_in_words && classifier.is_word(char) {
21875            return true;
21876        }
21877
21878        buffer.completion_triggers().contains(text)
21879    }
21880}
21881
21882impl SemanticsProvider for Entity<Project> {
21883    fn hover(
21884        &self,
21885        buffer: &Entity<Buffer>,
21886        position: text::Anchor,
21887        cx: &mut App,
21888    ) -> Option<Task<Vec<project::Hover>>> {
21889        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21890    }
21891
21892    fn document_highlights(
21893        &self,
21894        buffer: &Entity<Buffer>,
21895        position: text::Anchor,
21896        cx: &mut App,
21897    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21898        Some(self.update(cx, |project, cx| {
21899            project.document_highlights(buffer, position, cx)
21900        }))
21901    }
21902
21903    fn definitions(
21904        &self,
21905        buffer: &Entity<Buffer>,
21906        position: text::Anchor,
21907        kind: GotoDefinitionKind,
21908        cx: &mut App,
21909    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21910        Some(self.update(cx, |project, cx| match kind {
21911            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21912            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21913            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21914            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21915        }))
21916    }
21917
21918    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21919        // TODO: make this work for remote projects
21920        self.update(cx, |project, cx| {
21921            if project
21922                .active_debug_session(cx)
21923                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21924            {
21925                return true;
21926            }
21927
21928            buffer.update(cx, |buffer, cx| {
21929                project.any_language_server_supports_inlay_hints(buffer, cx)
21930            })
21931        })
21932    }
21933
21934    fn inline_values(
21935        &self,
21936        buffer_handle: Entity<Buffer>,
21937        range: Range<text::Anchor>,
21938        cx: &mut App,
21939    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21940        self.update(cx, |project, cx| {
21941            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21942
21943            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21944        })
21945    }
21946
21947    fn inlay_hints(
21948        &self,
21949        buffer_handle: Entity<Buffer>,
21950        range: Range<text::Anchor>,
21951        cx: &mut App,
21952    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21953        Some(self.update(cx, |project, cx| {
21954            project.inlay_hints(buffer_handle, range, cx)
21955        }))
21956    }
21957
21958    fn resolve_inlay_hint(
21959        &self,
21960        hint: InlayHint,
21961        buffer_handle: Entity<Buffer>,
21962        server_id: LanguageServerId,
21963        cx: &mut App,
21964    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21965        Some(self.update(cx, |project, cx| {
21966            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21967        }))
21968    }
21969
21970    fn range_for_rename(
21971        &self,
21972        buffer: &Entity<Buffer>,
21973        position: text::Anchor,
21974        cx: &mut App,
21975    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21976        Some(self.update(cx, |project, cx| {
21977            let buffer = buffer.clone();
21978            let task = project.prepare_rename(buffer.clone(), position, cx);
21979            cx.spawn(async move |_, cx| {
21980                Ok(match task.await? {
21981                    PrepareRenameResponse::Success(range) => Some(range),
21982                    PrepareRenameResponse::InvalidPosition => None,
21983                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21984                        // Fallback on using TreeSitter info to determine identifier range
21985                        buffer.read_with(cx, |buffer, _| {
21986                            let snapshot = buffer.snapshot();
21987                            let (range, kind) = snapshot.surrounding_word(position);
21988                            if kind != Some(CharKind::Word) {
21989                                return None;
21990                            }
21991                            Some(
21992                                snapshot.anchor_before(range.start)
21993                                    ..snapshot.anchor_after(range.end),
21994                            )
21995                        })?
21996                    }
21997                })
21998            })
21999        }))
22000    }
22001
22002    fn perform_rename(
22003        &self,
22004        buffer: &Entity<Buffer>,
22005        position: text::Anchor,
22006        new_name: String,
22007        cx: &mut App,
22008    ) -> Option<Task<Result<ProjectTransaction>>> {
22009        Some(self.update(cx, |project, cx| {
22010            project.perform_rename(buffer.clone(), position, new_name, cx)
22011        }))
22012    }
22013}
22014
22015fn inlay_hint_settings(
22016    location: Anchor,
22017    snapshot: &MultiBufferSnapshot,
22018    cx: &mut Context<Editor>,
22019) -> InlayHintSettings {
22020    let file = snapshot.file_at(location);
22021    let language = snapshot.language_at(location).map(|l| l.name());
22022    language_settings(language, file, cx).inlay_hints
22023}
22024
22025fn consume_contiguous_rows(
22026    contiguous_row_selections: &mut Vec<Selection<Point>>,
22027    selection: &Selection<Point>,
22028    display_map: &DisplaySnapshot,
22029    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22030) -> (MultiBufferRow, MultiBufferRow) {
22031    contiguous_row_selections.push(selection.clone());
22032    let start_row = MultiBufferRow(selection.start.row);
22033    let mut end_row = ending_row(selection, display_map);
22034
22035    while let Some(next_selection) = selections.peek() {
22036        if next_selection.start.row <= end_row.0 {
22037            end_row = ending_row(next_selection, display_map);
22038            contiguous_row_selections.push(selections.next().unwrap().clone());
22039        } else {
22040            break;
22041        }
22042    }
22043    (start_row, end_row)
22044}
22045
22046fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22047    if next_selection.end.column > 0 || next_selection.is_empty() {
22048        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22049    } else {
22050        MultiBufferRow(next_selection.end.row)
22051    }
22052}
22053
22054impl EditorSnapshot {
22055    pub fn remote_selections_in_range<'a>(
22056        &'a self,
22057        range: &'a Range<Anchor>,
22058        collaboration_hub: &dyn CollaborationHub,
22059        cx: &'a App,
22060    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22061        let participant_names = collaboration_hub.user_names(cx);
22062        let participant_indices = collaboration_hub.user_participant_indices(cx);
22063        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22064        let collaborators_by_replica_id = collaborators_by_peer_id
22065            .values()
22066            .map(|collaborator| (collaborator.replica_id, collaborator))
22067            .collect::<HashMap<_, _>>();
22068        self.buffer_snapshot
22069            .selections_in_range(range, false)
22070            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22071                if replica_id == AGENT_REPLICA_ID {
22072                    Some(RemoteSelection {
22073                        replica_id,
22074                        selection,
22075                        cursor_shape,
22076                        line_mode,
22077                        collaborator_id: CollaboratorId::Agent,
22078                        user_name: Some("Agent".into()),
22079                        color: cx.theme().players().agent(),
22080                    })
22081                } else {
22082                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22083                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22084                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22085                    Some(RemoteSelection {
22086                        replica_id,
22087                        selection,
22088                        cursor_shape,
22089                        line_mode,
22090                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22091                        user_name,
22092                        color: if let Some(index) = participant_index {
22093                            cx.theme().players().color_for_participant(index.0)
22094                        } else {
22095                            cx.theme().players().absent()
22096                        },
22097                    })
22098                }
22099            })
22100    }
22101
22102    pub fn hunks_for_ranges(
22103        &self,
22104        ranges: impl IntoIterator<Item = Range<Point>>,
22105    ) -> Vec<MultiBufferDiffHunk> {
22106        let mut hunks = Vec::new();
22107        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22108            HashMap::default();
22109        for query_range in ranges {
22110            let query_rows =
22111                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22112            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22113                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22114            ) {
22115                // Include deleted hunks that are adjacent to the query range, because
22116                // otherwise they would be missed.
22117                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22118                if hunk.status().is_deleted() {
22119                    intersects_range |= hunk.row_range.start == query_rows.end;
22120                    intersects_range |= hunk.row_range.end == query_rows.start;
22121                }
22122                if intersects_range {
22123                    if !processed_buffer_rows
22124                        .entry(hunk.buffer_id)
22125                        .or_default()
22126                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22127                    {
22128                        continue;
22129                    }
22130                    hunks.push(hunk);
22131                }
22132            }
22133        }
22134
22135        hunks
22136    }
22137
22138    fn display_diff_hunks_for_rows<'a>(
22139        &'a self,
22140        display_rows: Range<DisplayRow>,
22141        folded_buffers: &'a HashSet<BufferId>,
22142    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22143        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22144        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22145
22146        self.buffer_snapshot
22147            .diff_hunks_in_range(buffer_start..buffer_end)
22148            .filter_map(|hunk| {
22149                if folded_buffers.contains(&hunk.buffer_id) {
22150                    return None;
22151                }
22152
22153                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22154                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22155
22156                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22157                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22158
22159                let display_hunk = if hunk_display_start.column() != 0 {
22160                    DisplayDiffHunk::Folded {
22161                        display_row: hunk_display_start.row(),
22162                    }
22163                } else {
22164                    let mut end_row = hunk_display_end.row();
22165                    if hunk_display_end.column() > 0 {
22166                        end_row.0 += 1;
22167                    }
22168                    let is_created_file = hunk.is_created_file();
22169                    DisplayDiffHunk::Unfolded {
22170                        status: hunk.status(),
22171                        diff_base_byte_range: hunk.diff_base_byte_range,
22172                        display_row_range: hunk_display_start.row()..end_row,
22173                        multi_buffer_range: Anchor::range_in_buffer(
22174                            hunk.excerpt_id,
22175                            hunk.buffer_id,
22176                            hunk.buffer_range,
22177                        ),
22178                        is_created_file,
22179                    }
22180                };
22181
22182                Some(display_hunk)
22183            })
22184    }
22185
22186    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22187        self.display_snapshot.buffer_snapshot.language_at(position)
22188    }
22189
22190    pub fn is_focused(&self) -> bool {
22191        self.is_focused
22192    }
22193
22194    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22195        self.placeholder_text.as_ref()
22196    }
22197
22198    pub fn scroll_position(&self) -> gpui::Point<f32> {
22199        self.scroll_anchor.scroll_position(&self.display_snapshot)
22200    }
22201
22202    fn gutter_dimensions(
22203        &self,
22204        font_id: FontId,
22205        font_size: Pixels,
22206        max_line_number_width: Pixels,
22207        cx: &App,
22208    ) -> Option<GutterDimensions> {
22209        if !self.show_gutter {
22210            return None;
22211        }
22212
22213        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22214        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22215
22216        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22217            matches!(
22218                ProjectSettings::get_global(cx).git.git_gutter,
22219                Some(GitGutterSetting::TrackedFiles)
22220            )
22221        });
22222        let gutter_settings = EditorSettings::get_global(cx).gutter;
22223        let show_line_numbers = self
22224            .show_line_numbers
22225            .unwrap_or(gutter_settings.line_numbers);
22226        let line_gutter_width = if show_line_numbers {
22227            // Avoid flicker-like gutter resizes when the line number gains another digit by
22228            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22229            let min_width_for_number_on_gutter =
22230                ch_advance * gutter_settings.min_line_number_digits as f32;
22231            max_line_number_width.max(min_width_for_number_on_gutter)
22232        } else {
22233            0.0.into()
22234        };
22235
22236        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22237        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22238
22239        let git_blame_entries_width =
22240            self.git_blame_gutter_max_author_length
22241                .map(|max_author_length| {
22242                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22243                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22244
22245                    /// The number of characters to dedicate to gaps and margins.
22246                    const SPACING_WIDTH: usize = 4;
22247
22248                    let max_char_count = max_author_length.min(renderer.max_author_length())
22249                        + ::git::SHORT_SHA_LENGTH
22250                        + MAX_RELATIVE_TIMESTAMP.len()
22251                        + SPACING_WIDTH;
22252
22253                    ch_advance * max_char_count
22254                });
22255
22256        let is_singleton = self.buffer_snapshot.is_singleton();
22257
22258        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22259        left_padding += if !is_singleton {
22260            ch_width * 4.0
22261        } else if show_runnables || show_breakpoints {
22262            ch_width * 3.0
22263        } else if show_git_gutter && show_line_numbers {
22264            ch_width * 2.0
22265        } else if show_git_gutter || show_line_numbers {
22266            ch_width
22267        } else {
22268            px(0.)
22269        };
22270
22271        let shows_folds = is_singleton && gutter_settings.folds;
22272
22273        let right_padding = if shows_folds && show_line_numbers {
22274            ch_width * 4.0
22275        } else if shows_folds || (!is_singleton && show_line_numbers) {
22276            ch_width * 3.0
22277        } else if show_line_numbers {
22278            ch_width
22279        } else {
22280            px(0.)
22281        };
22282
22283        Some(GutterDimensions {
22284            left_padding,
22285            right_padding,
22286            width: line_gutter_width + left_padding + right_padding,
22287            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22288            git_blame_entries_width,
22289        })
22290    }
22291
22292    pub fn render_crease_toggle(
22293        &self,
22294        buffer_row: MultiBufferRow,
22295        row_contains_cursor: bool,
22296        editor: Entity<Editor>,
22297        window: &mut Window,
22298        cx: &mut App,
22299    ) -> Option<AnyElement> {
22300        let folded = self.is_line_folded(buffer_row);
22301        let mut is_foldable = false;
22302
22303        if let Some(crease) = self
22304            .crease_snapshot
22305            .query_row(buffer_row, &self.buffer_snapshot)
22306        {
22307            is_foldable = true;
22308            match crease {
22309                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22310                    if let Some(render_toggle) = render_toggle {
22311                        let toggle_callback =
22312                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22313                                if folded {
22314                                    editor.update(cx, |editor, cx| {
22315                                        editor.fold_at(buffer_row, window, cx)
22316                                    });
22317                                } else {
22318                                    editor.update(cx, |editor, cx| {
22319                                        editor.unfold_at(buffer_row, window, cx)
22320                                    });
22321                                }
22322                            });
22323                        return Some((render_toggle)(
22324                            buffer_row,
22325                            folded,
22326                            toggle_callback,
22327                            window,
22328                            cx,
22329                        ));
22330                    }
22331                }
22332            }
22333        }
22334
22335        is_foldable |= self.starts_indent(buffer_row);
22336
22337        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22338            Some(
22339                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22340                    .toggle_state(folded)
22341                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22342                        if folded {
22343                            this.unfold_at(buffer_row, window, cx);
22344                        } else {
22345                            this.fold_at(buffer_row, window, cx);
22346                        }
22347                    }))
22348                    .into_any_element(),
22349            )
22350        } else {
22351            None
22352        }
22353    }
22354
22355    pub fn render_crease_trailer(
22356        &self,
22357        buffer_row: MultiBufferRow,
22358        window: &mut Window,
22359        cx: &mut App,
22360    ) -> Option<AnyElement> {
22361        let folded = self.is_line_folded(buffer_row);
22362        if let Crease::Inline { render_trailer, .. } = self
22363            .crease_snapshot
22364            .query_row(buffer_row, &self.buffer_snapshot)?
22365        {
22366            let render_trailer = render_trailer.as_ref()?;
22367            Some(render_trailer(buffer_row, folded, window, cx))
22368        } else {
22369            None
22370        }
22371    }
22372}
22373
22374impl Deref for EditorSnapshot {
22375    type Target = DisplaySnapshot;
22376
22377    fn deref(&self) -> &Self::Target {
22378        &self.display_snapshot
22379    }
22380}
22381
22382#[derive(Clone, Debug, PartialEq, Eq)]
22383pub enum EditorEvent {
22384    InputIgnored {
22385        text: Arc<str>,
22386    },
22387    InputHandled {
22388        utf16_range_to_replace: Option<Range<isize>>,
22389        text: Arc<str>,
22390    },
22391    ExcerptsAdded {
22392        buffer: Entity<Buffer>,
22393        predecessor: ExcerptId,
22394        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22395    },
22396    ExcerptsRemoved {
22397        ids: Vec<ExcerptId>,
22398        removed_buffer_ids: Vec<BufferId>,
22399    },
22400    BufferFoldToggled {
22401        ids: Vec<ExcerptId>,
22402        folded: bool,
22403    },
22404    ExcerptsEdited {
22405        ids: Vec<ExcerptId>,
22406    },
22407    ExcerptsExpanded {
22408        ids: Vec<ExcerptId>,
22409    },
22410    BufferEdited,
22411    Edited {
22412        transaction_id: clock::Lamport,
22413    },
22414    Reparsed(BufferId),
22415    Focused,
22416    FocusedIn,
22417    Blurred,
22418    DirtyChanged,
22419    Saved,
22420    TitleChanged,
22421    DiffBaseChanged,
22422    SelectionsChanged {
22423        local: bool,
22424    },
22425    ScrollPositionChanged {
22426        local: bool,
22427        autoscroll: bool,
22428    },
22429    Closed,
22430    TransactionUndone {
22431        transaction_id: clock::Lamport,
22432    },
22433    TransactionBegun {
22434        transaction_id: clock::Lamport,
22435    },
22436    Reloaded,
22437    CursorShapeChanged,
22438    PushedToNavHistory {
22439        anchor: Anchor,
22440        is_deactivate: bool,
22441    },
22442}
22443
22444impl EventEmitter<EditorEvent> for Editor {}
22445
22446impl Focusable for Editor {
22447    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22448        self.focus_handle.clone()
22449    }
22450}
22451
22452impl Render for Editor {
22453    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22454        let settings = ThemeSettings::get_global(cx);
22455
22456        let mut text_style = match self.mode {
22457            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22458                color: cx.theme().colors().editor_foreground,
22459                font_family: settings.ui_font.family.clone(),
22460                font_features: settings.ui_font.features.clone(),
22461                font_fallbacks: settings.ui_font.fallbacks.clone(),
22462                font_size: rems(0.875).into(),
22463                font_weight: settings.ui_font.weight,
22464                line_height: relative(settings.buffer_line_height.value()),
22465                ..Default::default()
22466            },
22467            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22468                color: cx.theme().colors().editor_foreground,
22469                font_family: settings.buffer_font.family.clone(),
22470                font_features: settings.buffer_font.features.clone(),
22471                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22472                font_size: settings.buffer_font_size(cx).into(),
22473                font_weight: settings.buffer_font.weight,
22474                line_height: relative(settings.buffer_line_height.value()),
22475                ..Default::default()
22476            },
22477        };
22478        if let Some(text_style_refinement) = &self.text_style_refinement {
22479            text_style.refine(text_style_refinement)
22480        }
22481
22482        let background = match self.mode {
22483            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22484            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22485            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22486            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22487        };
22488
22489        EditorElement::new(
22490            &cx.entity(),
22491            EditorStyle {
22492                background,
22493                border: cx.theme().colors().border,
22494                local_player: cx.theme().players().local(),
22495                text: text_style,
22496                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22497                syntax: cx.theme().syntax().clone(),
22498                status: cx.theme().status().clone(),
22499                inlay_hints_style: make_inlay_hints_style(cx),
22500                inline_completion_styles: make_suggestion_styles(cx),
22501                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22502                show_underlines: self.diagnostics_enabled(),
22503            },
22504        )
22505    }
22506}
22507
22508impl EntityInputHandler for Editor {
22509    fn text_for_range(
22510        &mut self,
22511        range_utf16: Range<usize>,
22512        adjusted_range: &mut Option<Range<usize>>,
22513        _: &mut Window,
22514        cx: &mut Context<Self>,
22515    ) -> Option<String> {
22516        let snapshot = self.buffer.read(cx).read(cx);
22517        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22518        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22519        if (start.0..end.0) != range_utf16 {
22520            adjusted_range.replace(start.0..end.0);
22521        }
22522        Some(snapshot.text_for_range(start..end).collect())
22523    }
22524
22525    fn selected_text_range(
22526        &mut self,
22527        ignore_disabled_input: bool,
22528        _: &mut Window,
22529        cx: &mut Context<Self>,
22530    ) -> Option<UTF16Selection> {
22531        // Prevent the IME menu from appearing when holding down an alphabetic key
22532        // while input is disabled.
22533        if !ignore_disabled_input && !self.input_enabled {
22534            return None;
22535        }
22536
22537        let selection = self.selections.newest::<OffsetUtf16>(cx);
22538        let range = selection.range();
22539
22540        Some(UTF16Selection {
22541            range: range.start.0..range.end.0,
22542            reversed: selection.reversed,
22543        })
22544    }
22545
22546    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22547        let snapshot = self.buffer.read(cx).read(cx);
22548        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22549        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22550    }
22551
22552    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22553        self.clear_highlights::<InputComposition>(cx);
22554        self.ime_transaction.take();
22555    }
22556
22557    fn replace_text_in_range(
22558        &mut self,
22559        range_utf16: Option<Range<usize>>,
22560        text: &str,
22561        window: &mut Window,
22562        cx: &mut Context<Self>,
22563    ) {
22564        if !self.input_enabled {
22565            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22566            return;
22567        }
22568
22569        self.transact(window, cx, |this, window, cx| {
22570            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22571                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22572                Some(this.selection_replacement_ranges(range_utf16, cx))
22573            } else {
22574                this.marked_text_ranges(cx)
22575            };
22576
22577            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22578                let newest_selection_id = this.selections.newest_anchor().id;
22579                this.selections
22580                    .all::<OffsetUtf16>(cx)
22581                    .iter()
22582                    .zip(ranges_to_replace.iter())
22583                    .find_map(|(selection, range)| {
22584                        if selection.id == newest_selection_id {
22585                            Some(
22586                                (range.start.0 as isize - selection.head().0 as isize)
22587                                    ..(range.end.0 as isize - selection.head().0 as isize),
22588                            )
22589                        } else {
22590                            None
22591                        }
22592                    })
22593            });
22594
22595            cx.emit(EditorEvent::InputHandled {
22596                utf16_range_to_replace: range_to_replace,
22597                text: text.into(),
22598            });
22599
22600            if let Some(new_selected_ranges) = new_selected_ranges {
22601                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22602                    selections.select_ranges(new_selected_ranges)
22603                });
22604                this.backspace(&Default::default(), window, cx);
22605            }
22606
22607            this.handle_input(text, window, cx);
22608        });
22609
22610        if let Some(transaction) = self.ime_transaction {
22611            self.buffer.update(cx, |buffer, cx| {
22612                buffer.group_until_transaction(transaction, cx);
22613            });
22614        }
22615
22616        self.unmark_text(window, cx);
22617    }
22618
22619    fn replace_and_mark_text_in_range(
22620        &mut self,
22621        range_utf16: Option<Range<usize>>,
22622        text: &str,
22623        new_selected_range_utf16: Option<Range<usize>>,
22624        window: &mut Window,
22625        cx: &mut Context<Self>,
22626    ) {
22627        if !self.input_enabled {
22628            return;
22629        }
22630
22631        let transaction = self.transact(window, cx, |this, window, cx| {
22632            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22633                let snapshot = this.buffer.read(cx).read(cx);
22634                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22635                    for marked_range in &mut marked_ranges {
22636                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22637                        marked_range.start.0 += relative_range_utf16.start;
22638                        marked_range.start =
22639                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22640                        marked_range.end =
22641                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22642                    }
22643                }
22644                Some(marked_ranges)
22645            } else if let Some(range_utf16) = range_utf16 {
22646                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22647                Some(this.selection_replacement_ranges(range_utf16, cx))
22648            } else {
22649                None
22650            };
22651
22652            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22653                let newest_selection_id = this.selections.newest_anchor().id;
22654                this.selections
22655                    .all::<OffsetUtf16>(cx)
22656                    .iter()
22657                    .zip(ranges_to_replace.iter())
22658                    .find_map(|(selection, range)| {
22659                        if selection.id == newest_selection_id {
22660                            Some(
22661                                (range.start.0 as isize - selection.head().0 as isize)
22662                                    ..(range.end.0 as isize - selection.head().0 as isize),
22663                            )
22664                        } else {
22665                            None
22666                        }
22667                    })
22668            });
22669
22670            cx.emit(EditorEvent::InputHandled {
22671                utf16_range_to_replace: range_to_replace,
22672                text: text.into(),
22673            });
22674
22675            if let Some(ranges) = ranges_to_replace {
22676                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22677                    s.select_ranges(ranges)
22678                });
22679            }
22680
22681            let marked_ranges = {
22682                let snapshot = this.buffer.read(cx).read(cx);
22683                this.selections
22684                    .disjoint_anchors()
22685                    .iter()
22686                    .map(|selection| {
22687                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22688                    })
22689                    .collect::<Vec<_>>()
22690            };
22691
22692            if text.is_empty() {
22693                this.unmark_text(window, cx);
22694            } else {
22695                this.highlight_text::<InputComposition>(
22696                    marked_ranges.clone(),
22697                    HighlightStyle {
22698                        underline: Some(UnderlineStyle {
22699                            thickness: px(1.),
22700                            color: None,
22701                            wavy: false,
22702                        }),
22703                        ..Default::default()
22704                    },
22705                    cx,
22706                );
22707            }
22708
22709            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22710            let use_autoclose = this.use_autoclose;
22711            let use_auto_surround = this.use_auto_surround;
22712            this.set_use_autoclose(false);
22713            this.set_use_auto_surround(false);
22714            this.handle_input(text, window, cx);
22715            this.set_use_autoclose(use_autoclose);
22716            this.set_use_auto_surround(use_auto_surround);
22717
22718            if let Some(new_selected_range) = new_selected_range_utf16 {
22719                let snapshot = this.buffer.read(cx).read(cx);
22720                let new_selected_ranges = marked_ranges
22721                    .into_iter()
22722                    .map(|marked_range| {
22723                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22724                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22725                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22726                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22727                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22728                    })
22729                    .collect::<Vec<_>>();
22730
22731                drop(snapshot);
22732                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22733                    selections.select_ranges(new_selected_ranges)
22734                });
22735            }
22736        });
22737
22738        self.ime_transaction = self.ime_transaction.or(transaction);
22739        if let Some(transaction) = self.ime_transaction {
22740            self.buffer.update(cx, |buffer, cx| {
22741                buffer.group_until_transaction(transaction, cx);
22742            });
22743        }
22744
22745        if self.text_highlights::<InputComposition>(cx).is_none() {
22746            self.ime_transaction.take();
22747        }
22748    }
22749
22750    fn bounds_for_range(
22751        &mut self,
22752        range_utf16: Range<usize>,
22753        element_bounds: gpui::Bounds<Pixels>,
22754        window: &mut Window,
22755        cx: &mut Context<Self>,
22756    ) -> Option<gpui::Bounds<Pixels>> {
22757        let text_layout_details = self.text_layout_details(window);
22758        let CharacterDimensions {
22759            em_width,
22760            em_advance,
22761            line_height,
22762        } = self.character_dimensions(window);
22763
22764        let snapshot = self.snapshot(window, cx);
22765        let scroll_position = snapshot.scroll_position();
22766        let scroll_left = scroll_position.x * em_advance;
22767
22768        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22769        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22770            + self.gutter_dimensions.full_width();
22771        let y = line_height * (start.row().as_f32() - scroll_position.y);
22772
22773        Some(Bounds {
22774            origin: element_bounds.origin + point(x, y),
22775            size: size(em_width, line_height),
22776        })
22777    }
22778
22779    fn character_index_for_point(
22780        &mut self,
22781        point: gpui::Point<Pixels>,
22782        _window: &mut Window,
22783        _cx: &mut Context<Self>,
22784    ) -> Option<usize> {
22785        let position_map = self.last_position_map.as_ref()?;
22786        if !position_map.text_hitbox.contains(&point) {
22787            return None;
22788        }
22789        let display_point = position_map.point_for_position(point).previous_valid;
22790        let anchor = position_map
22791            .snapshot
22792            .display_point_to_anchor(display_point, Bias::Left);
22793        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22794        Some(utf16_offset.0)
22795    }
22796}
22797
22798trait SelectionExt {
22799    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22800    fn spanned_rows(
22801        &self,
22802        include_end_if_at_line_start: bool,
22803        map: &DisplaySnapshot,
22804    ) -> Range<MultiBufferRow>;
22805}
22806
22807impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22808    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22809        let start = self
22810            .start
22811            .to_point(&map.buffer_snapshot)
22812            .to_display_point(map);
22813        let end = self
22814            .end
22815            .to_point(&map.buffer_snapshot)
22816            .to_display_point(map);
22817        if self.reversed {
22818            end..start
22819        } else {
22820            start..end
22821        }
22822    }
22823
22824    fn spanned_rows(
22825        &self,
22826        include_end_if_at_line_start: bool,
22827        map: &DisplaySnapshot,
22828    ) -> Range<MultiBufferRow> {
22829        let start = self.start.to_point(&map.buffer_snapshot);
22830        let mut end = self.end.to_point(&map.buffer_snapshot);
22831        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22832            end.row -= 1;
22833        }
22834
22835        let buffer_start = map.prev_line_boundary(start).0;
22836        let buffer_end = map.next_line_boundary(end).0;
22837        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22838    }
22839}
22840
22841impl<T: InvalidationRegion> InvalidationStack<T> {
22842    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22843    where
22844        S: Clone + ToOffset,
22845    {
22846        while let Some(region) = self.last() {
22847            let all_selections_inside_invalidation_ranges =
22848                if selections.len() == region.ranges().len() {
22849                    selections
22850                        .iter()
22851                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22852                        .all(|(selection, invalidation_range)| {
22853                            let head = selection.head().to_offset(buffer);
22854                            invalidation_range.start <= head && invalidation_range.end >= head
22855                        })
22856                } else {
22857                    false
22858                };
22859
22860            if all_selections_inside_invalidation_ranges {
22861                break;
22862            } else {
22863                self.pop();
22864            }
22865        }
22866    }
22867}
22868
22869impl<T> Default for InvalidationStack<T> {
22870    fn default() -> Self {
22871        Self(Default::default())
22872    }
22873}
22874
22875impl<T> Deref for InvalidationStack<T> {
22876    type Target = Vec<T>;
22877
22878    fn deref(&self) -> &Self::Target {
22879        &self.0
22880    }
22881}
22882
22883impl<T> DerefMut for InvalidationStack<T> {
22884    fn deref_mut(&mut self) -> &mut Self::Target {
22885        &mut self.0
22886    }
22887}
22888
22889impl InvalidationRegion for SnippetState {
22890    fn ranges(&self) -> &[Range<Anchor>] {
22891        &self.ranges[self.active_index]
22892    }
22893}
22894
22895fn inline_completion_edit_text(
22896    current_snapshot: &BufferSnapshot,
22897    edits: &[(Range<Anchor>, String)],
22898    edit_preview: &EditPreview,
22899    include_deletions: bool,
22900    cx: &App,
22901) -> HighlightedText {
22902    let edits = edits
22903        .iter()
22904        .map(|(anchor, text)| {
22905            (
22906                anchor.start.text_anchor..anchor.end.text_anchor,
22907                text.clone(),
22908            )
22909        })
22910        .collect::<Vec<_>>();
22911
22912    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22913}
22914
22915pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22916    match severity {
22917        lsp::DiagnosticSeverity::ERROR => colors.error,
22918        lsp::DiagnosticSeverity::WARNING => colors.warning,
22919        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22920        lsp::DiagnosticSeverity::HINT => colors.info,
22921        _ => colors.ignored,
22922    }
22923}
22924
22925pub fn styled_runs_for_code_label<'a>(
22926    label: &'a CodeLabel,
22927    syntax_theme: &'a theme::SyntaxTheme,
22928) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22929    let fade_out = HighlightStyle {
22930        fade_out: Some(0.35),
22931        ..Default::default()
22932    };
22933
22934    let mut prev_end = label.filter_range.end;
22935    label
22936        .runs
22937        .iter()
22938        .enumerate()
22939        .flat_map(move |(ix, (range, highlight_id))| {
22940            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22941                style
22942            } else {
22943                return Default::default();
22944            };
22945            let mut muted_style = style;
22946            muted_style.highlight(fade_out);
22947
22948            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22949            if range.start >= label.filter_range.end {
22950                if range.start > prev_end {
22951                    runs.push((prev_end..range.start, fade_out));
22952                }
22953                runs.push((range.clone(), muted_style));
22954            } else if range.end <= label.filter_range.end {
22955                runs.push((range.clone(), style));
22956            } else {
22957                runs.push((range.start..label.filter_range.end, style));
22958                runs.push((label.filter_range.end..range.end, muted_style));
22959            }
22960            prev_end = cmp::max(prev_end, range.end);
22961
22962            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22963                runs.push((prev_end..label.text.len(), fade_out));
22964            }
22965
22966            runs
22967        })
22968}
22969
22970pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22971    let mut prev_index = 0;
22972    let mut prev_codepoint: Option<char> = None;
22973    text.char_indices()
22974        .chain([(text.len(), '\0')])
22975        .filter_map(move |(index, codepoint)| {
22976            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22977            let is_boundary = index == text.len()
22978                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22979                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22980            if is_boundary {
22981                let chunk = &text[prev_index..index];
22982                prev_index = index;
22983                Some(chunk)
22984            } else {
22985                None
22986            }
22987        })
22988}
22989
22990pub trait RangeToAnchorExt: Sized {
22991    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22992
22993    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22994        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22995        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22996    }
22997}
22998
22999impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23000    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23001        let start_offset = self.start.to_offset(snapshot);
23002        let end_offset = self.end.to_offset(snapshot);
23003        if start_offset == end_offset {
23004            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23005        } else {
23006            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23007        }
23008    }
23009}
23010
23011pub trait RowExt {
23012    fn as_f32(&self) -> f32;
23013
23014    fn next_row(&self) -> Self;
23015
23016    fn previous_row(&self) -> Self;
23017
23018    fn minus(&self, other: Self) -> u32;
23019}
23020
23021impl RowExt for DisplayRow {
23022    fn as_f32(&self) -> f32 {
23023        self.0 as f32
23024    }
23025
23026    fn next_row(&self) -> Self {
23027        Self(self.0 + 1)
23028    }
23029
23030    fn previous_row(&self) -> Self {
23031        Self(self.0.saturating_sub(1))
23032    }
23033
23034    fn minus(&self, other: Self) -> u32 {
23035        self.0 - other.0
23036    }
23037}
23038
23039impl RowExt for MultiBufferRow {
23040    fn as_f32(&self) -> f32 {
23041        self.0 as f32
23042    }
23043
23044    fn next_row(&self) -> Self {
23045        Self(self.0 + 1)
23046    }
23047
23048    fn previous_row(&self) -> Self {
23049        Self(self.0.saturating_sub(1))
23050    }
23051
23052    fn minus(&self, other: Self) -> u32 {
23053        self.0 - other.0
23054    }
23055}
23056
23057trait RowRangeExt {
23058    type Row;
23059
23060    fn len(&self) -> usize;
23061
23062    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23063}
23064
23065impl RowRangeExt for Range<MultiBufferRow> {
23066    type Row = MultiBufferRow;
23067
23068    fn len(&self) -> usize {
23069        (self.end.0 - self.start.0) as usize
23070    }
23071
23072    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23073        (self.start.0..self.end.0).map(MultiBufferRow)
23074    }
23075}
23076
23077impl RowRangeExt for Range<DisplayRow> {
23078    type Row = DisplayRow;
23079
23080    fn len(&self) -> usize {
23081        (self.end.0 - self.start.0) as usize
23082    }
23083
23084    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23085        (self.start.0..self.end.0).map(DisplayRow)
23086    }
23087}
23088
23089/// If select range has more than one line, we
23090/// just point the cursor to range.start.
23091fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23092    if range.start.row == range.end.row {
23093        range
23094    } else {
23095        range.start..range.start
23096    }
23097}
23098pub struct KillRing(ClipboardItem);
23099impl Global for KillRing {}
23100
23101const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23102
23103enum BreakpointPromptEditAction {
23104    Log,
23105    Condition,
23106    HitCondition,
23107}
23108
23109struct BreakpointPromptEditor {
23110    pub(crate) prompt: Entity<Editor>,
23111    editor: WeakEntity<Editor>,
23112    breakpoint_anchor: Anchor,
23113    breakpoint: Breakpoint,
23114    edit_action: BreakpointPromptEditAction,
23115    block_ids: HashSet<CustomBlockId>,
23116    editor_margins: Arc<Mutex<EditorMargins>>,
23117    _subscriptions: Vec<Subscription>,
23118}
23119
23120impl BreakpointPromptEditor {
23121    const MAX_LINES: u8 = 4;
23122
23123    fn new(
23124        editor: WeakEntity<Editor>,
23125        breakpoint_anchor: Anchor,
23126        breakpoint: Breakpoint,
23127        edit_action: BreakpointPromptEditAction,
23128        window: &mut Window,
23129        cx: &mut Context<Self>,
23130    ) -> Self {
23131        let base_text = match edit_action {
23132            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23133            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23134            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23135        }
23136        .map(|msg| msg.to_string())
23137        .unwrap_or_default();
23138
23139        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23140        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23141
23142        let prompt = cx.new(|cx| {
23143            let mut prompt = Editor::new(
23144                EditorMode::AutoHeight {
23145                    min_lines: 1,
23146                    max_lines: Some(Self::MAX_LINES as usize),
23147                },
23148                buffer,
23149                None,
23150                window,
23151                cx,
23152            );
23153            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23154            prompt.set_show_cursor_when_unfocused(false, cx);
23155            prompt.set_placeholder_text(
23156                match edit_action {
23157                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23158                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23159                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23160                },
23161                cx,
23162            );
23163
23164            prompt
23165        });
23166
23167        Self {
23168            prompt,
23169            editor,
23170            breakpoint_anchor,
23171            breakpoint,
23172            edit_action,
23173            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23174            block_ids: Default::default(),
23175            _subscriptions: vec![],
23176        }
23177    }
23178
23179    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23180        self.block_ids.extend(block_ids)
23181    }
23182
23183    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23184        if let Some(editor) = self.editor.upgrade() {
23185            let message = self
23186                .prompt
23187                .read(cx)
23188                .buffer
23189                .read(cx)
23190                .as_singleton()
23191                .expect("A multi buffer in breakpoint prompt isn't possible")
23192                .read(cx)
23193                .as_rope()
23194                .to_string();
23195
23196            editor.update(cx, |editor, cx| {
23197                editor.edit_breakpoint_at_anchor(
23198                    self.breakpoint_anchor,
23199                    self.breakpoint.clone(),
23200                    match self.edit_action {
23201                        BreakpointPromptEditAction::Log => {
23202                            BreakpointEditAction::EditLogMessage(message.into())
23203                        }
23204                        BreakpointPromptEditAction::Condition => {
23205                            BreakpointEditAction::EditCondition(message.into())
23206                        }
23207                        BreakpointPromptEditAction::HitCondition => {
23208                            BreakpointEditAction::EditHitCondition(message.into())
23209                        }
23210                    },
23211                    cx,
23212                );
23213
23214                editor.remove_blocks(self.block_ids.clone(), None, cx);
23215                cx.focus_self(window);
23216            });
23217        }
23218    }
23219
23220    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23221        self.editor
23222            .update(cx, |editor, cx| {
23223                editor.remove_blocks(self.block_ids.clone(), None, cx);
23224                window.focus(&editor.focus_handle);
23225            })
23226            .log_err();
23227    }
23228
23229    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23230        let settings = ThemeSettings::get_global(cx);
23231        let text_style = TextStyle {
23232            color: if self.prompt.read(cx).read_only(cx) {
23233                cx.theme().colors().text_disabled
23234            } else {
23235                cx.theme().colors().text
23236            },
23237            font_family: settings.buffer_font.family.clone(),
23238            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23239            font_size: settings.buffer_font_size(cx).into(),
23240            font_weight: settings.buffer_font.weight,
23241            line_height: relative(settings.buffer_line_height.value()),
23242            ..Default::default()
23243        };
23244        EditorElement::new(
23245            &self.prompt,
23246            EditorStyle {
23247                background: cx.theme().colors().editor_background,
23248                local_player: cx.theme().players().local(),
23249                text: text_style,
23250                ..Default::default()
23251            },
23252        )
23253    }
23254}
23255
23256impl Render for BreakpointPromptEditor {
23257    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23258        let editor_margins = *self.editor_margins.lock();
23259        let gutter_dimensions = editor_margins.gutter;
23260        h_flex()
23261            .key_context("Editor")
23262            .bg(cx.theme().colors().editor_background)
23263            .border_y_1()
23264            .border_color(cx.theme().status().info_border)
23265            .size_full()
23266            .py(window.line_height() / 2.5)
23267            .on_action(cx.listener(Self::confirm))
23268            .on_action(cx.listener(Self::cancel))
23269            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23270            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23271    }
23272}
23273
23274impl Focusable for BreakpointPromptEditor {
23275    fn focus_handle(&self, cx: &App) -> FocusHandle {
23276        self.prompt.focus_handle(cx)
23277    }
23278}
23279
23280fn all_edits_insertions_or_deletions(
23281    edits: &Vec<(Range<Anchor>, String)>,
23282    snapshot: &MultiBufferSnapshot,
23283) -> bool {
23284    let mut all_insertions = true;
23285    let mut all_deletions = true;
23286
23287    for (range, new_text) in edits.iter() {
23288        let range_is_empty = range.to_offset(&snapshot).is_empty();
23289        let text_is_empty = new_text.is_empty();
23290
23291        if range_is_empty != text_is_empty {
23292            if range_is_empty {
23293                all_deletions = false;
23294            } else {
23295                all_insertions = false;
23296            }
23297        } else {
23298            return false;
23299        }
23300
23301        if !all_insertions && !all_deletions {
23302            return false;
23303        }
23304    }
23305    all_insertions || all_deletions
23306}
23307
23308struct MissingEditPredictionKeybindingTooltip;
23309
23310impl Render for MissingEditPredictionKeybindingTooltip {
23311    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23312        ui::tooltip_container(window, cx, |container, _, cx| {
23313            container
23314                .flex_shrink_0()
23315                .max_w_80()
23316                .min_h(rems_from_px(124.))
23317                .justify_between()
23318                .child(
23319                    v_flex()
23320                        .flex_1()
23321                        .text_ui_sm(cx)
23322                        .child(Label::new("Conflict with Accept Keybinding"))
23323                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23324                )
23325                .child(
23326                    h_flex()
23327                        .pb_1()
23328                        .gap_1()
23329                        .items_end()
23330                        .w_full()
23331                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23332                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23333                        }))
23334                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23335                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23336                        })),
23337                )
23338        })
23339    }
23340}
23341
23342#[derive(Debug, Clone, Copy, PartialEq)]
23343pub struct LineHighlight {
23344    pub background: Background,
23345    pub border: Option<gpui::Hsla>,
23346    pub include_gutter: bool,
23347    pub type_id: Option<TypeId>,
23348}
23349
23350struct LineManipulationResult {
23351    pub new_text: String,
23352    pub line_count_before: usize,
23353    pub line_count_after: usize,
23354}
23355
23356fn render_diff_hunk_controls(
23357    row: u32,
23358    status: &DiffHunkStatus,
23359    hunk_range: Range<Anchor>,
23360    is_created_file: bool,
23361    line_height: Pixels,
23362    editor: &Entity<Editor>,
23363    _window: &mut Window,
23364    cx: &mut App,
23365) -> AnyElement {
23366    h_flex()
23367        .h(line_height)
23368        .mr_1()
23369        .gap_1()
23370        .px_0p5()
23371        .pb_1()
23372        .border_x_1()
23373        .border_b_1()
23374        .border_color(cx.theme().colors().border_variant)
23375        .rounded_b_lg()
23376        .bg(cx.theme().colors().editor_background)
23377        .gap_1()
23378        .block_mouse_except_scroll()
23379        .shadow_md()
23380        .child(if status.has_secondary_hunk() {
23381            Button::new(("stage", row as u64), "Stage")
23382                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23383                .tooltip({
23384                    let focus_handle = editor.focus_handle(cx);
23385                    move |window, cx| {
23386                        Tooltip::for_action_in(
23387                            "Stage Hunk",
23388                            &::git::ToggleStaged,
23389                            &focus_handle,
23390                            window,
23391                            cx,
23392                        )
23393                    }
23394                })
23395                .on_click({
23396                    let editor = editor.clone();
23397                    move |_event, _window, cx| {
23398                        editor.update(cx, |editor, cx| {
23399                            editor.stage_or_unstage_diff_hunks(
23400                                true,
23401                                vec![hunk_range.start..hunk_range.start],
23402                                cx,
23403                            );
23404                        });
23405                    }
23406                })
23407        } else {
23408            Button::new(("unstage", row as u64), "Unstage")
23409                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23410                .tooltip({
23411                    let focus_handle = editor.focus_handle(cx);
23412                    move |window, cx| {
23413                        Tooltip::for_action_in(
23414                            "Unstage Hunk",
23415                            &::git::ToggleStaged,
23416                            &focus_handle,
23417                            window,
23418                            cx,
23419                        )
23420                    }
23421                })
23422                .on_click({
23423                    let editor = editor.clone();
23424                    move |_event, _window, cx| {
23425                        editor.update(cx, |editor, cx| {
23426                            editor.stage_or_unstage_diff_hunks(
23427                                false,
23428                                vec![hunk_range.start..hunk_range.start],
23429                                cx,
23430                            );
23431                        });
23432                    }
23433                })
23434        })
23435        .child(
23436            Button::new(("restore", row as u64), "Restore")
23437                .tooltip({
23438                    let focus_handle = editor.focus_handle(cx);
23439                    move |window, cx| {
23440                        Tooltip::for_action_in(
23441                            "Restore Hunk",
23442                            &::git::Restore,
23443                            &focus_handle,
23444                            window,
23445                            cx,
23446                        )
23447                    }
23448                })
23449                .on_click({
23450                    let editor = editor.clone();
23451                    move |_event, window, cx| {
23452                        editor.update(cx, |editor, cx| {
23453                            let snapshot = editor.snapshot(window, cx);
23454                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23455                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23456                        });
23457                    }
23458                })
23459                .disabled(is_created_file),
23460        )
23461        .when(
23462            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23463            |el| {
23464                el.child(
23465                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23466                        .shape(IconButtonShape::Square)
23467                        .icon_size(IconSize::Small)
23468                        // .disabled(!has_multiple_hunks)
23469                        .tooltip({
23470                            let focus_handle = editor.focus_handle(cx);
23471                            move |window, cx| {
23472                                Tooltip::for_action_in(
23473                                    "Next Hunk",
23474                                    &GoToHunk,
23475                                    &focus_handle,
23476                                    window,
23477                                    cx,
23478                                )
23479                            }
23480                        })
23481                        .on_click({
23482                            let editor = editor.clone();
23483                            move |_event, window, cx| {
23484                                editor.update(cx, |editor, cx| {
23485                                    let snapshot = editor.snapshot(window, cx);
23486                                    let position =
23487                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23488                                    editor.go_to_hunk_before_or_after_position(
23489                                        &snapshot,
23490                                        position,
23491                                        Direction::Next,
23492                                        window,
23493                                        cx,
23494                                    );
23495                                    editor.expand_selected_diff_hunks(cx);
23496                                });
23497                            }
23498                        }),
23499                )
23500                .child(
23501                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23502                        .shape(IconButtonShape::Square)
23503                        .icon_size(IconSize::Small)
23504                        // .disabled(!has_multiple_hunks)
23505                        .tooltip({
23506                            let focus_handle = editor.focus_handle(cx);
23507                            move |window, cx| {
23508                                Tooltip::for_action_in(
23509                                    "Previous Hunk",
23510                                    &GoToPreviousHunk,
23511                                    &focus_handle,
23512                                    window,
23513                                    cx,
23514                                )
23515                            }
23516                        })
23517                        .on_click({
23518                            let editor = editor.clone();
23519                            move |_event, window, cx| {
23520                                editor.update(cx, |editor, cx| {
23521                                    let snapshot = editor.snapshot(window, cx);
23522                                    let point =
23523                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23524                                    editor.go_to_hunk_before_or_after_position(
23525                                        &snapshot,
23526                                        point,
23527                                        Direction::Prev,
23528                                        window,
23529                                        cx,
23530                                    );
23531                                    editor.expand_selected_diff_hunks(cx);
23532                                });
23533                            }
23534                        }),
23535                )
23536            },
23537        )
23538        .into_any_element()
23539}