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(scenario, context, Some(buffer), window, cx);
 6190                });
 6191                Some(Task::ready(Ok(())))
 6192            }
 6193        }
 6194    }
 6195
 6196    pub async fn open_project_transaction(
 6197        this: &WeakEntity<Editor>,
 6198        workspace: WeakEntity<Workspace>,
 6199        transaction: ProjectTransaction,
 6200        title: String,
 6201        cx: &mut AsyncWindowContext,
 6202    ) -> Result<()> {
 6203        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6204        cx.update(|_, cx| {
 6205            entries.sort_unstable_by_key(|(buffer, _)| {
 6206                buffer.read(cx).file().map(|f| f.path().clone())
 6207            });
 6208        })?;
 6209
 6210        // If the project transaction's edits are all contained within this editor, then
 6211        // avoid opening a new editor to display them.
 6212
 6213        if let Some((buffer, transaction)) = entries.first() {
 6214            if entries.len() == 1 {
 6215                let excerpt = this.update(cx, |editor, cx| {
 6216                    editor
 6217                        .buffer()
 6218                        .read(cx)
 6219                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6220                })?;
 6221                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6222                    if excerpted_buffer == *buffer {
 6223                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6224                            let excerpt_range = excerpt_range.to_offset(buffer);
 6225                            buffer
 6226                                .edited_ranges_for_transaction::<usize>(transaction)
 6227                                .all(|range| {
 6228                                    excerpt_range.start <= range.start
 6229                                        && excerpt_range.end >= range.end
 6230                                })
 6231                        })?;
 6232
 6233                        if all_edits_within_excerpt {
 6234                            return Ok(());
 6235                        }
 6236                    }
 6237                }
 6238            }
 6239        } else {
 6240            return Ok(());
 6241        }
 6242
 6243        let mut ranges_to_highlight = Vec::new();
 6244        let excerpt_buffer = cx.new(|cx| {
 6245            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6246            for (buffer_handle, transaction) in &entries {
 6247                let edited_ranges = buffer_handle
 6248                    .read(cx)
 6249                    .edited_ranges_for_transaction::<Point>(transaction)
 6250                    .collect::<Vec<_>>();
 6251                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6252                    PathKey::for_buffer(buffer_handle, cx),
 6253                    buffer_handle.clone(),
 6254                    edited_ranges,
 6255                    DEFAULT_MULTIBUFFER_CONTEXT,
 6256                    cx,
 6257                );
 6258
 6259                ranges_to_highlight.extend(ranges);
 6260            }
 6261            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6262            multibuffer
 6263        })?;
 6264
 6265        workspace.update_in(cx, |workspace, window, cx| {
 6266            let project = workspace.project().clone();
 6267            let editor =
 6268                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6269            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6270            editor.update(cx, |editor, cx| {
 6271                editor.highlight_background::<Self>(
 6272                    &ranges_to_highlight,
 6273                    |theme| theme.colors().editor_highlighted_line_background,
 6274                    cx,
 6275                );
 6276            });
 6277        })?;
 6278
 6279        Ok(())
 6280    }
 6281
 6282    pub fn clear_code_action_providers(&mut self) {
 6283        self.code_action_providers.clear();
 6284        self.available_code_actions.take();
 6285    }
 6286
 6287    pub fn add_code_action_provider(
 6288        &mut self,
 6289        provider: Rc<dyn CodeActionProvider>,
 6290        window: &mut Window,
 6291        cx: &mut Context<Self>,
 6292    ) {
 6293        if self
 6294            .code_action_providers
 6295            .iter()
 6296            .any(|existing_provider| existing_provider.id() == provider.id())
 6297        {
 6298            return;
 6299        }
 6300
 6301        self.code_action_providers.push(provider);
 6302        self.refresh_code_actions(window, cx);
 6303    }
 6304
 6305    pub fn remove_code_action_provider(
 6306        &mut self,
 6307        id: Arc<str>,
 6308        window: &mut Window,
 6309        cx: &mut Context<Self>,
 6310    ) {
 6311        self.code_action_providers
 6312            .retain(|provider| provider.id() != id);
 6313        self.refresh_code_actions(window, cx);
 6314    }
 6315
 6316    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6317        !self.code_action_providers.is_empty()
 6318            && EditorSettings::get_global(cx).toolbar.code_actions
 6319    }
 6320
 6321    pub fn has_available_code_actions(&self) -> bool {
 6322        self.available_code_actions
 6323            .as_ref()
 6324            .is_some_and(|(_, actions)| !actions.is_empty())
 6325    }
 6326
 6327    fn render_inline_code_actions(
 6328        &self,
 6329        icon_size: ui::IconSize,
 6330        display_row: DisplayRow,
 6331        is_active: bool,
 6332        cx: &mut Context<Self>,
 6333    ) -> AnyElement {
 6334        let show_tooltip = !self.context_menu_visible();
 6335        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6336            .icon_size(icon_size)
 6337            .shape(ui::IconButtonShape::Square)
 6338            .style(ButtonStyle::Transparent)
 6339            .icon_color(ui::Color::Hidden)
 6340            .toggle_state(is_active)
 6341            .when(show_tooltip, |this| {
 6342                this.tooltip({
 6343                    let focus_handle = self.focus_handle.clone();
 6344                    move |window, cx| {
 6345                        Tooltip::for_action_in(
 6346                            "Toggle Code Actions",
 6347                            &ToggleCodeActions {
 6348                                deployed_from: None,
 6349                                quick_launch: false,
 6350                            },
 6351                            &focus_handle,
 6352                            window,
 6353                            cx,
 6354                        )
 6355                    }
 6356                })
 6357            })
 6358            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6359                window.focus(&editor.focus_handle(cx));
 6360                editor.toggle_code_actions(
 6361                    &crate::actions::ToggleCodeActions {
 6362                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6363                            display_row,
 6364                        )),
 6365                        quick_launch: false,
 6366                    },
 6367                    window,
 6368                    cx,
 6369                );
 6370            }))
 6371            .into_any_element()
 6372    }
 6373
 6374    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6375        &self.context_menu
 6376    }
 6377
 6378    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6379        let newest_selection = self.selections.newest_anchor().clone();
 6380        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6381        let buffer = self.buffer.read(cx);
 6382        if newest_selection.head().diff_base_anchor.is_some() {
 6383            return None;
 6384        }
 6385        let (start_buffer, start) =
 6386            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6387        let (end_buffer, end) =
 6388            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6389        if start_buffer != end_buffer {
 6390            return None;
 6391        }
 6392
 6393        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6394            cx.background_executor()
 6395                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6396                .await;
 6397
 6398            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6399                let providers = this.code_action_providers.clone();
 6400                let tasks = this
 6401                    .code_action_providers
 6402                    .iter()
 6403                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6404                    .collect::<Vec<_>>();
 6405                (providers, tasks)
 6406            })?;
 6407
 6408            let mut actions = Vec::new();
 6409            for (provider, provider_actions) in
 6410                providers.into_iter().zip(future::join_all(tasks).await)
 6411            {
 6412                if let Some(provider_actions) = provider_actions.log_err() {
 6413                    actions.extend(provider_actions.into_iter().map(|action| {
 6414                        AvailableCodeAction {
 6415                            excerpt_id: newest_selection.start.excerpt_id,
 6416                            action,
 6417                            provider: provider.clone(),
 6418                        }
 6419                    }));
 6420                }
 6421            }
 6422
 6423            this.update(cx, |this, cx| {
 6424                this.available_code_actions = if actions.is_empty() {
 6425                    None
 6426                } else {
 6427                    Some((
 6428                        Location {
 6429                            buffer: start_buffer,
 6430                            range: start..end,
 6431                        },
 6432                        actions.into(),
 6433                    ))
 6434                };
 6435                cx.notify();
 6436            })
 6437        }));
 6438        None
 6439    }
 6440
 6441    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6442        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6443            self.show_git_blame_inline = false;
 6444
 6445            self.show_git_blame_inline_delay_task =
 6446                Some(cx.spawn_in(window, async move |this, cx| {
 6447                    cx.background_executor().timer(delay).await;
 6448
 6449                    this.update(cx, |this, cx| {
 6450                        this.show_git_blame_inline = true;
 6451                        cx.notify();
 6452                    })
 6453                    .log_err();
 6454                }));
 6455        }
 6456    }
 6457
 6458    fn show_blame_popover(
 6459        &mut self,
 6460        blame_entry: &BlameEntry,
 6461        position: gpui::Point<Pixels>,
 6462        cx: &mut Context<Self>,
 6463    ) {
 6464        if let Some(state) = &mut self.inline_blame_popover {
 6465            state.hide_task.take();
 6466        } else {
 6467            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6468            let blame_entry = blame_entry.clone();
 6469            let show_task = cx.spawn(async move |editor, cx| {
 6470                cx.background_executor()
 6471                    .timer(std::time::Duration::from_millis(delay))
 6472                    .await;
 6473                editor
 6474                    .update(cx, |editor, cx| {
 6475                        editor.inline_blame_popover_show_task.take();
 6476                        let Some(blame) = editor.blame.as_ref() else {
 6477                            return;
 6478                        };
 6479                        let blame = blame.read(cx);
 6480                        let details = blame.details_for_entry(&blame_entry);
 6481                        let markdown = cx.new(|cx| {
 6482                            Markdown::new(
 6483                                details
 6484                                    .as_ref()
 6485                                    .map(|message| message.message.clone())
 6486                                    .unwrap_or_default(),
 6487                                None,
 6488                                None,
 6489                                cx,
 6490                            )
 6491                        });
 6492                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6493                            position,
 6494                            hide_task: None,
 6495                            popover_bounds: None,
 6496                            popover_state: InlineBlamePopoverState {
 6497                                scroll_handle: ScrollHandle::new(),
 6498                                commit_message: details,
 6499                                markdown,
 6500                            },
 6501                        });
 6502                        cx.notify();
 6503                    })
 6504                    .ok();
 6505            });
 6506            self.inline_blame_popover_show_task = Some(show_task);
 6507        }
 6508    }
 6509
 6510    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6511        self.inline_blame_popover_show_task.take();
 6512        if let Some(state) = &mut self.inline_blame_popover {
 6513            let hide_task = cx.spawn(async move |editor, cx| {
 6514                cx.background_executor()
 6515                    .timer(std::time::Duration::from_millis(100))
 6516                    .await;
 6517                editor
 6518                    .update(cx, |editor, cx| {
 6519                        editor.inline_blame_popover.take();
 6520                        cx.notify();
 6521                    })
 6522                    .ok();
 6523            });
 6524            state.hide_task = Some(hide_task);
 6525        }
 6526    }
 6527
 6528    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6529        if self.pending_rename.is_some() {
 6530            return None;
 6531        }
 6532
 6533        let provider = self.semantics_provider.clone()?;
 6534        let buffer = self.buffer.read(cx);
 6535        let newest_selection = self.selections.newest_anchor().clone();
 6536        let cursor_position = newest_selection.head();
 6537        let (cursor_buffer, cursor_buffer_position) =
 6538            buffer.text_anchor_for_position(cursor_position, cx)?;
 6539        let (tail_buffer, tail_buffer_position) =
 6540            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6541        if cursor_buffer != tail_buffer {
 6542            return None;
 6543        }
 6544
 6545        let snapshot = cursor_buffer.read(cx).snapshot();
 6546        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6547        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6548        if start_word_range != end_word_range {
 6549            self.document_highlights_task.take();
 6550            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6551            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6552            return None;
 6553        }
 6554
 6555        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6556        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6557            cx.background_executor()
 6558                .timer(Duration::from_millis(debounce))
 6559                .await;
 6560
 6561            let highlights = if let Some(highlights) = cx
 6562                .update(|cx| {
 6563                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6564                })
 6565                .ok()
 6566                .flatten()
 6567            {
 6568                highlights.await.log_err()
 6569            } else {
 6570                None
 6571            };
 6572
 6573            if let Some(highlights) = highlights {
 6574                this.update(cx, |this, cx| {
 6575                    if this.pending_rename.is_some() {
 6576                        return;
 6577                    }
 6578
 6579                    let buffer_id = cursor_position.buffer_id;
 6580                    let buffer = this.buffer.read(cx);
 6581                    if !buffer
 6582                        .text_anchor_for_position(cursor_position, cx)
 6583                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6584                    {
 6585                        return;
 6586                    }
 6587
 6588                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6589                    let mut write_ranges = Vec::new();
 6590                    let mut read_ranges = Vec::new();
 6591                    for highlight in highlights {
 6592                        for (excerpt_id, excerpt_range) in
 6593                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6594                        {
 6595                            let start = highlight
 6596                                .range
 6597                                .start
 6598                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6599                            let end = highlight
 6600                                .range
 6601                                .end
 6602                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6603                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6604                                continue;
 6605                            }
 6606
 6607                            let range = Anchor {
 6608                                buffer_id,
 6609                                excerpt_id,
 6610                                text_anchor: start,
 6611                                diff_base_anchor: None,
 6612                            }..Anchor {
 6613                                buffer_id,
 6614                                excerpt_id,
 6615                                text_anchor: end,
 6616                                diff_base_anchor: None,
 6617                            };
 6618                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6619                                write_ranges.push(range);
 6620                            } else {
 6621                                read_ranges.push(range);
 6622                            }
 6623                        }
 6624                    }
 6625
 6626                    this.highlight_background::<DocumentHighlightRead>(
 6627                        &read_ranges,
 6628                        |theme| theme.colors().editor_document_highlight_read_background,
 6629                        cx,
 6630                    );
 6631                    this.highlight_background::<DocumentHighlightWrite>(
 6632                        &write_ranges,
 6633                        |theme| theme.colors().editor_document_highlight_write_background,
 6634                        cx,
 6635                    );
 6636                    cx.notify();
 6637                })
 6638                .log_err();
 6639            }
 6640        }));
 6641        None
 6642    }
 6643
 6644    fn prepare_highlight_query_from_selection(
 6645        &mut self,
 6646        cx: &mut Context<Editor>,
 6647    ) -> Option<(String, Range<Anchor>)> {
 6648        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6649            return None;
 6650        }
 6651        if !EditorSettings::get_global(cx).selection_highlight {
 6652            return None;
 6653        }
 6654        if self.selections.count() != 1 || self.selections.line_mode {
 6655            return None;
 6656        }
 6657        let selection = self.selections.newest::<Point>(cx);
 6658        if selection.is_empty() || selection.start.row != selection.end.row {
 6659            return None;
 6660        }
 6661        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6662        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6663        let query = multi_buffer_snapshot
 6664            .text_for_range(selection_anchor_range.clone())
 6665            .collect::<String>();
 6666        if query.trim().is_empty() {
 6667            return None;
 6668        }
 6669        Some((query, selection_anchor_range))
 6670    }
 6671
 6672    fn update_selection_occurrence_highlights(
 6673        &mut self,
 6674        query_text: String,
 6675        query_range: Range<Anchor>,
 6676        multi_buffer_range_to_query: Range<Point>,
 6677        use_debounce: bool,
 6678        window: &mut Window,
 6679        cx: &mut Context<Editor>,
 6680    ) -> Task<()> {
 6681        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6682        cx.spawn_in(window, async move |editor, cx| {
 6683            if use_debounce {
 6684                cx.background_executor()
 6685                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6686                    .await;
 6687            }
 6688            let match_task = cx.background_spawn(async move {
 6689                let buffer_ranges = multi_buffer_snapshot
 6690                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6691                    .into_iter()
 6692                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6693                let mut match_ranges = Vec::new();
 6694                let Ok(regex) = project::search::SearchQuery::text(
 6695                    query_text.clone(),
 6696                    false,
 6697                    false,
 6698                    false,
 6699                    Default::default(),
 6700                    Default::default(),
 6701                    false,
 6702                    None,
 6703                ) else {
 6704                    return Vec::default();
 6705                };
 6706                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6707                    match_ranges.extend(
 6708                        regex
 6709                            .search(&buffer_snapshot, Some(search_range.clone()))
 6710                            .await
 6711                            .into_iter()
 6712                            .filter_map(|match_range| {
 6713                                let match_start = buffer_snapshot
 6714                                    .anchor_after(search_range.start + match_range.start);
 6715                                let match_end = buffer_snapshot
 6716                                    .anchor_before(search_range.start + match_range.end);
 6717                                let match_anchor_range = Anchor::range_in_buffer(
 6718                                    excerpt_id,
 6719                                    buffer_snapshot.remote_id(),
 6720                                    match_start..match_end,
 6721                                );
 6722                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6723                            }),
 6724                    );
 6725                }
 6726                match_ranges
 6727            });
 6728            let match_ranges = match_task.await;
 6729            editor
 6730                .update_in(cx, |editor, _, cx| {
 6731                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6732                    if !match_ranges.is_empty() {
 6733                        editor.highlight_background::<SelectedTextHighlight>(
 6734                            &match_ranges,
 6735                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6736                            cx,
 6737                        )
 6738                    }
 6739                })
 6740                .log_err();
 6741        })
 6742    }
 6743
 6744    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6745        struct NewlineFold;
 6746        let type_id = std::any::TypeId::of::<NewlineFold>();
 6747        if !self.mode.is_single_line() {
 6748            return;
 6749        }
 6750        let snapshot = self.snapshot(window, cx);
 6751        if snapshot.buffer_snapshot.max_point().row == 0 {
 6752            return;
 6753        }
 6754        let task = cx.background_spawn(async move {
 6755            let new_newlines = snapshot
 6756                .buffer_chars_at(0)
 6757                .filter_map(|(c, i)| {
 6758                    if c == '\n' {
 6759                        Some(
 6760                            snapshot.buffer_snapshot.anchor_after(i)
 6761                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6762                        )
 6763                    } else {
 6764                        None
 6765                    }
 6766                })
 6767                .collect::<Vec<_>>();
 6768            let existing_newlines = snapshot
 6769                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6770                .filter_map(|fold| {
 6771                    if fold.placeholder.type_tag == Some(type_id) {
 6772                        Some(fold.range.start..fold.range.end)
 6773                    } else {
 6774                        None
 6775                    }
 6776                })
 6777                .collect::<Vec<_>>();
 6778
 6779            (new_newlines, existing_newlines)
 6780        });
 6781        self.folding_newlines = cx.spawn(async move |this, cx| {
 6782            let (new_newlines, existing_newlines) = task.await;
 6783            if new_newlines == existing_newlines {
 6784                return;
 6785            }
 6786            let placeholder = FoldPlaceholder {
 6787                render: Arc::new(move |_, _, cx| {
 6788                    div()
 6789                        .bg(cx.theme().status().hint_background)
 6790                        .border_b_1()
 6791                        .size_full()
 6792                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6793                        .border_color(cx.theme().status().hint)
 6794                        .child("\\n")
 6795                        .into_any()
 6796                }),
 6797                constrain_width: false,
 6798                merge_adjacent: false,
 6799                type_tag: Some(type_id),
 6800            };
 6801            let creases = new_newlines
 6802                .into_iter()
 6803                .map(|range| Crease::simple(range, placeholder.clone()))
 6804                .collect();
 6805            this.update(cx, |this, cx| {
 6806                this.display_map.update(cx, |display_map, cx| {
 6807                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6808                    display_map.fold(creases, cx);
 6809                });
 6810            })
 6811            .ok();
 6812        });
 6813    }
 6814
 6815    fn refresh_selected_text_highlights(
 6816        &mut self,
 6817        on_buffer_edit: bool,
 6818        window: &mut Window,
 6819        cx: &mut Context<Editor>,
 6820    ) {
 6821        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6822        else {
 6823            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6824            self.quick_selection_highlight_task.take();
 6825            self.debounced_selection_highlight_task.take();
 6826            return;
 6827        };
 6828        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6829        if on_buffer_edit
 6830            || self
 6831                .quick_selection_highlight_task
 6832                .as_ref()
 6833                .map_or(true, |(prev_anchor_range, _)| {
 6834                    prev_anchor_range != &query_range
 6835                })
 6836        {
 6837            let multi_buffer_visible_start = self
 6838                .scroll_manager
 6839                .anchor()
 6840                .anchor
 6841                .to_point(&multi_buffer_snapshot);
 6842            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6843                multi_buffer_visible_start
 6844                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6845                Bias::Left,
 6846            );
 6847            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6848            self.quick_selection_highlight_task = Some((
 6849                query_range.clone(),
 6850                self.update_selection_occurrence_highlights(
 6851                    query_text.clone(),
 6852                    query_range.clone(),
 6853                    multi_buffer_visible_range,
 6854                    false,
 6855                    window,
 6856                    cx,
 6857                ),
 6858            ));
 6859        }
 6860        if on_buffer_edit
 6861            || self
 6862                .debounced_selection_highlight_task
 6863                .as_ref()
 6864                .map_or(true, |(prev_anchor_range, _)| {
 6865                    prev_anchor_range != &query_range
 6866                })
 6867        {
 6868            let multi_buffer_start = multi_buffer_snapshot
 6869                .anchor_before(0)
 6870                .to_point(&multi_buffer_snapshot);
 6871            let multi_buffer_end = multi_buffer_snapshot
 6872                .anchor_after(multi_buffer_snapshot.len())
 6873                .to_point(&multi_buffer_snapshot);
 6874            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6875            self.debounced_selection_highlight_task = Some((
 6876                query_range.clone(),
 6877                self.update_selection_occurrence_highlights(
 6878                    query_text,
 6879                    query_range,
 6880                    multi_buffer_full_range,
 6881                    true,
 6882                    window,
 6883                    cx,
 6884                ),
 6885            ));
 6886        }
 6887    }
 6888
 6889    pub fn refresh_inline_completion(
 6890        &mut self,
 6891        debounce: bool,
 6892        user_requested: bool,
 6893        window: &mut Window,
 6894        cx: &mut Context<Self>,
 6895    ) -> Option<()> {
 6896        let provider = self.edit_prediction_provider()?;
 6897        let cursor = self.selections.newest_anchor().head();
 6898        let (buffer, cursor_buffer_position) =
 6899            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6900
 6901        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6902            self.discard_inline_completion(false, cx);
 6903            return None;
 6904        }
 6905
 6906        if !user_requested
 6907            && (!self.should_show_edit_predictions()
 6908                || !self.is_focused(window)
 6909                || buffer.read(cx).is_empty())
 6910        {
 6911            self.discard_inline_completion(false, cx);
 6912            return None;
 6913        }
 6914
 6915        self.update_visible_inline_completion(window, cx);
 6916        provider.refresh(
 6917            self.project.clone(),
 6918            buffer,
 6919            cursor_buffer_position,
 6920            debounce,
 6921            cx,
 6922        );
 6923        Some(())
 6924    }
 6925
 6926    fn show_edit_predictions_in_menu(&self) -> bool {
 6927        match self.edit_prediction_settings {
 6928            EditPredictionSettings::Disabled => false,
 6929            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6930        }
 6931    }
 6932
 6933    pub fn edit_predictions_enabled(&self) -> bool {
 6934        match self.edit_prediction_settings {
 6935            EditPredictionSettings::Disabled => false,
 6936            EditPredictionSettings::Enabled { .. } => true,
 6937        }
 6938    }
 6939
 6940    fn edit_prediction_requires_modifier(&self) -> bool {
 6941        match self.edit_prediction_settings {
 6942            EditPredictionSettings::Disabled => false,
 6943            EditPredictionSettings::Enabled {
 6944                preview_requires_modifier,
 6945                ..
 6946            } => preview_requires_modifier,
 6947        }
 6948    }
 6949
 6950    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6951        if self.edit_prediction_provider.is_none() {
 6952            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6953        } else {
 6954            let selection = self.selections.newest_anchor();
 6955            let cursor = selection.head();
 6956
 6957            if let Some((buffer, cursor_buffer_position)) =
 6958                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6959            {
 6960                self.edit_prediction_settings =
 6961                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6962            }
 6963        }
 6964    }
 6965
 6966    fn edit_prediction_settings_at_position(
 6967        &self,
 6968        buffer: &Entity<Buffer>,
 6969        buffer_position: language::Anchor,
 6970        cx: &App,
 6971    ) -> EditPredictionSettings {
 6972        if !self.mode.is_full()
 6973            || !self.show_inline_completions_override.unwrap_or(true)
 6974            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6975        {
 6976            return EditPredictionSettings::Disabled;
 6977        }
 6978
 6979        let buffer = buffer.read(cx);
 6980
 6981        let file = buffer.file();
 6982
 6983        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6984            return EditPredictionSettings::Disabled;
 6985        };
 6986
 6987        let by_provider = matches!(
 6988            self.menu_inline_completions_policy,
 6989            MenuInlineCompletionsPolicy::ByProvider
 6990        );
 6991
 6992        let show_in_menu = by_provider
 6993            && self
 6994                .edit_prediction_provider
 6995                .as_ref()
 6996                .map_or(false, |provider| {
 6997                    provider.provider.show_completions_in_menu()
 6998                });
 6999
 7000        let preview_requires_modifier =
 7001            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7002
 7003        EditPredictionSettings::Enabled {
 7004            show_in_menu,
 7005            preview_requires_modifier,
 7006        }
 7007    }
 7008
 7009    fn should_show_edit_predictions(&self) -> bool {
 7010        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7011    }
 7012
 7013    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7014        matches!(
 7015            self.edit_prediction_preview,
 7016            EditPredictionPreview::Active { .. }
 7017        )
 7018    }
 7019
 7020    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7021        let cursor = self.selections.newest_anchor().head();
 7022        if let Some((buffer, cursor_position)) =
 7023            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7024        {
 7025            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7026        } else {
 7027            false
 7028        }
 7029    }
 7030
 7031    pub fn supports_minimap(&self, cx: &App) -> bool {
 7032        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7033    }
 7034
 7035    fn edit_predictions_enabled_in_buffer(
 7036        &self,
 7037        buffer: &Entity<Buffer>,
 7038        buffer_position: language::Anchor,
 7039        cx: &App,
 7040    ) -> bool {
 7041        maybe!({
 7042            if self.read_only(cx) {
 7043                return Some(false);
 7044            }
 7045            let provider = self.edit_prediction_provider()?;
 7046            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7047                return Some(false);
 7048            }
 7049            let buffer = buffer.read(cx);
 7050            let Some(file) = buffer.file() else {
 7051                return Some(true);
 7052            };
 7053            let settings = all_language_settings(Some(file), cx);
 7054            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7055        })
 7056        .unwrap_or(false)
 7057    }
 7058
 7059    fn cycle_inline_completion(
 7060        &mut self,
 7061        direction: Direction,
 7062        window: &mut Window,
 7063        cx: &mut Context<Self>,
 7064    ) -> Option<()> {
 7065        let provider = self.edit_prediction_provider()?;
 7066        let cursor = self.selections.newest_anchor().head();
 7067        let (buffer, cursor_buffer_position) =
 7068            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7069        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7070            return None;
 7071        }
 7072
 7073        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7074        self.update_visible_inline_completion(window, cx);
 7075
 7076        Some(())
 7077    }
 7078
 7079    pub fn show_inline_completion(
 7080        &mut self,
 7081        _: &ShowEditPrediction,
 7082        window: &mut Window,
 7083        cx: &mut Context<Self>,
 7084    ) {
 7085        if !self.has_active_inline_completion() {
 7086            self.refresh_inline_completion(false, true, window, cx);
 7087            return;
 7088        }
 7089
 7090        self.update_visible_inline_completion(window, cx);
 7091    }
 7092
 7093    pub fn display_cursor_names(
 7094        &mut self,
 7095        _: &DisplayCursorNames,
 7096        window: &mut Window,
 7097        cx: &mut Context<Self>,
 7098    ) {
 7099        self.show_cursor_names(window, cx);
 7100    }
 7101
 7102    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7103        self.show_cursor_names = true;
 7104        cx.notify();
 7105        cx.spawn_in(window, async move |this, cx| {
 7106            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7107            this.update(cx, |this, cx| {
 7108                this.show_cursor_names = false;
 7109                cx.notify()
 7110            })
 7111            .ok()
 7112        })
 7113        .detach();
 7114    }
 7115
 7116    pub fn next_edit_prediction(
 7117        &mut self,
 7118        _: &NextEditPrediction,
 7119        window: &mut Window,
 7120        cx: &mut Context<Self>,
 7121    ) {
 7122        if self.has_active_inline_completion() {
 7123            self.cycle_inline_completion(Direction::Next, window, cx);
 7124        } else {
 7125            let is_copilot_disabled = self
 7126                .refresh_inline_completion(false, true, window, cx)
 7127                .is_none();
 7128            if is_copilot_disabled {
 7129                cx.propagate();
 7130            }
 7131        }
 7132    }
 7133
 7134    pub fn previous_edit_prediction(
 7135        &mut self,
 7136        _: &PreviousEditPrediction,
 7137        window: &mut Window,
 7138        cx: &mut Context<Self>,
 7139    ) {
 7140        if self.has_active_inline_completion() {
 7141            self.cycle_inline_completion(Direction::Prev, window, cx);
 7142        } else {
 7143            let is_copilot_disabled = self
 7144                .refresh_inline_completion(false, true, window, cx)
 7145                .is_none();
 7146            if is_copilot_disabled {
 7147                cx.propagate();
 7148            }
 7149        }
 7150    }
 7151
 7152    pub fn accept_edit_prediction(
 7153        &mut self,
 7154        _: &AcceptEditPrediction,
 7155        window: &mut Window,
 7156        cx: &mut Context<Self>,
 7157    ) {
 7158        if self.show_edit_predictions_in_menu() {
 7159            self.hide_context_menu(window, cx);
 7160        }
 7161
 7162        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7163            return;
 7164        };
 7165
 7166        self.report_inline_completion_event(
 7167            active_inline_completion.completion_id.clone(),
 7168            true,
 7169            cx,
 7170        );
 7171
 7172        match &active_inline_completion.completion {
 7173            InlineCompletion::Move { target, .. } => {
 7174                let target = *target;
 7175
 7176                if let Some(position_map) = &self.last_position_map {
 7177                    if position_map
 7178                        .visible_row_range
 7179                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7180                        || !self.edit_prediction_requires_modifier()
 7181                    {
 7182                        self.unfold_ranges(&[target..target], true, false, cx);
 7183                        // Note that this is also done in vim's handler of the Tab action.
 7184                        self.change_selections(
 7185                            SelectionEffects::scroll(Autoscroll::newest()),
 7186                            window,
 7187                            cx,
 7188                            |selections| {
 7189                                selections.select_anchor_ranges([target..target]);
 7190                            },
 7191                        );
 7192                        self.clear_row_highlights::<EditPredictionPreview>();
 7193
 7194                        self.edit_prediction_preview
 7195                            .set_previous_scroll_position(None);
 7196                    } else {
 7197                        self.edit_prediction_preview
 7198                            .set_previous_scroll_position(Some(
 7199                                position_map.snapshot.scroll_anchor,
 7200                            ));
 7201
 7202                        self.highlight_rows::<EditPredictionPreview>(
 7203                            target..target,
 7204                            cx.theme().colors().editor_highlighted_line_background,
 7205                            RowHighlightOptions {
 7206                                autoscroll: true,
 7207                                ..Default::default()
 7208                            },
 7209                            cx,
 7210                        );
 7211                        self.request_autoscroll(Autoscroll::fit(), cx);
 7212                    }
 7213                }
 7214            }
 7215            InlineCompletion::Edit { edits, .. } => {
 7216                if let Some(provider) = self.edit_prediction_provider() {
 7217                    provider.accept(cx);
 7218                }
 7219
 7220                // Store the transaction ID and selections before applying the edit
 7221                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7222
 7223                let snapshot = self.buffer.read(cx).snapshot(cx);
 7224                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7225
 7226                self.buffer.update(cx, |buffer, cx| {
 7227                    buffer.edit(edits.iter().cloned(), None, cx)
 7228                });
 7229
 7230                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7231                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7232                });
 7233
 7234                let selections = self.selections.disjoint_anchors();
 7235                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7236                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7237                    if has_new_transaction {
 7238                        self.selection_history
 7239                            .insert_transaction(transaction_id_now, selections);
 7240                    }
 7241                }
 7242
 7243                self.update_visible_inline_completion(window, cx);
 7244                if self.active_inline_completion.is_none() {
 7245                    self.refresh_inline_completion(true, true, window, cx);
 7246                }
 7247
 7248                cx.notify();
 7249            }
 7250        }
 7251
 7252        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7253    }
 7254
 7255    pub fn accept_partial_inline_completion(
 7256        &mut self,
 7257        _: &AcceptPartialEditPrediction,
 7258        window: &mut Window,
 7259        cx: &mut Context<Self>,
 7260    ) {
 7261        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7262            return;
 7263        };
 7264        if self.selections.count() != 1 {
 7265            return;
 7266        }
 7267
 7268        self.report_inline_completion_event(
 7269            active_inline_completion.completion_id.clone(),
 7270            true,
 7271            cx,
 7272        );
 7273
 7274        match &active_inline_completion.completion {
 7275            InlineCompletion::Move { target, .. } => {
 7276                let target = *target;
 7277                self.change_selections(
 7278                    SelectionEffects::scroll(Autoscroll::newest()),
 7279                    window,
 7280                    cx,
 7281                    |selections| {
 7282                        selections.select_anchor_ranges([target..target]);
 7283                    },
 7284                );
 7285            }
 7286            InlineCompletion::Edit { edits, .. } => {
 7287                // Find an insertion that starts at the cursor position.
 7288                let snapshot = self.buffer.read(cx).snapshot(cx);
 7289                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7290                let insertion = edits.iter().find_map(|(range, text)| {
 7291                    let range = range.to_offset(&snapshot);
 7292                    if range.is_empty() && range.start == cursor_offset {
 7293                        Some(text)
 7294                    } else {
 7295                        None
 7296                    }
 7297                });
 7298
 7299                if let Some(text) = insertion {
 7300                    let mut partial_completion = text
 7301                        .chars()
 7302                        .by_ref()
 7303                        .take_while(|c| c.is_alphabetic())
 7304                        .collect::<String>();
 7305                    if partial_completion.is_empty() {
 7306                        partial_completion = text
 7307                            .chars()
 7308                            .by_ref()
 7309                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7310                            .collect::<String>();
 7311                    }
 7312
 7313                    cx.emit(EditorEvent::InputHandled {
 7314                        utf16_range_to_replace: None,
 7315                        text: partial_completion.clone().into(),
 7316                    });
 7317
 7318                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7319
 7320                    self.refresh_inline_completion(true, true, window, cx);
 7321                    cx.notify();
 7322                } else {
 7323                    self.accept_edit_prediction(&Default::default(), window, cx);
 7324                }
 7325            }
 7326        }
 7327    }
 7328
 7329    fn discard_inline_completion(
 7330        &mut self,
 7331        should_report_inline_completion_event: bool,
 7332        cx: &mut Context<Self>,
 7333    ) -> bool {
 7334        if should_report_inline_completion_event {
 7335            let completion_id = self
 7336                .active_inline_completion
 7337                .as_ref()
 7338                .and_then(|active_completion| active_completion.completion_id.clone());
 7339
 7340            self.report_inline_completion_event(completion_id, false, cx);
 7341        }
 7342
 7343        if let Some(provider) = self.edit_prediction_provider() {
 7344            provider.discard(cx);
 7345        }
 7346
 7347        self.take_active_inline_completion(cx)
 7348    }
 7349
 7350    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7351        let Some(provider) = self.edit_prediction_provider() else {
 7352            return;
 7353        };
 7354
 7355        let Some((_, buffer, _)) = self
 7356            .buffer
 7357            .read(cx)
 7358            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7359        else {
 7360            return;
 7361        };
 7362
 7363        let extension = buffer
 7364            .read(cx)
 7365            .file()
 7366            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7367
 7368        let event_type = match accepted {
 7369            true => "Edit Prediction Accepted",
 7370            false => "Edit Prediction Discarded",
 7371        };
 7372        telemetry::event!(
 7373            event_type,
 7374            provider = provider.name(),
 7375            prediction_id = id,
 7376            suggestion_accepted = accepted,
 7377            file_extension = extension,
 7378        );
 7379    }
 7380
 7381    pub fn has_active_inline_completion(&self) -> bool {
 7382        self.active_inline_completion.is_some()
 7383    }
 7384
 7385    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7386        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7387            return false;
 7388        };
 7389
 7390        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7391        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7392        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7393        true
 7394    }
 7395
 7396    /// Returns true when we're displaying the edit prediction popover below the cursor
 7397    /// like we are not previewing and the LSP autocomplete menu is visible
 7398    /// or we are in `when_holding_modifier` mode.
 7399    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7400        if self.edit_prediction_preview_is_active()
 7401            || !self.show_edit_predictions_in_menu()
 7402            || !self.edit_predictions_enabled()
 7403        {
 7404            return false;
 7405        }
 7406
 7407        if self.has_visible_completions_menu() {
 7408            return true;
 7409        }
 7410
 7411        has_completion && self.edit_prediction_requires_modifier()
 7412    }
 7413
 7414    fn handle_modifiers_changed(
 7415        &mut self,
 7416        modifiers: Modifiers,
 7417        position_map: &PositionMap,
 7418        window: &mut Window,
 7419        cx: &mut Context<Self>,
 7420    ) {
 7421        if self.show_edit_predictions_in_menu() {
 7422            self.update_edit_prediction_preview(&modifiers, window, cx);
 7423        }
 7424
 7425        self.update_selection_mode(&modifiers, position_map, window, cx);
 7426
 7427        let mouse_position = window.mouse_position();
 7428        if !position_map.text_hitbox.is_hovered(window) {
 7429            return;
 7430        }
 7431
 7432        self.update_hovered_link(
 7433            position_map.point_for_position(mouse_position),
 7434            &position_map.snapshot,
 7435            modifiers,
 7436            window,
 7437            cx,
 7438        )
 7439    }
 7440
 7441    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7442        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7443        if invert {
 7444            match multi_cursor_setting {
 7445                MultiCursorModifier::Alt => modifiers.alt,
 7446                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7447            }
 7448        } else {
 7449            match multi_cursor_setting {
 7450                MultiCursorModifier::Alt => modifiers.secondary(),
 7451                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7452            }
 7453        }
 7454    }
 7455
 7456    fn columnar_selection_mode(
 7457        modifiers: &Modifiers,
 7458        cx: &mut Context<Self>,
 7459    ) -> Option<ColumnarMode> {
 7460        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7461            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7462                Some(ColumnarMode::FromMouse)
 7463            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7464                Some(ColumnarMode::FromSelection)
 7465            } else {
 7466                None
 7467            }
 7468        } else {
 7469            None
 7470        }
 7471    }
 7472
 7473    fn update_selection_mode(
 7474        &mut self,
 7475        modifiers: &Modifiers,
 7476        position_map: &PositionMap,
 7477        window: &mut Window,
 7478        cx: &mut Context<Self>,
 7479    ) {
 7480        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7481            return;
 7482        };
 7483        if self.selections.pending.is_none() {
 7484            return;
 7485        }
 7486
 7487        let mouse_position = window.mouse_position();
 7488        let point_for_position = position_map.point_for_position(mouse_position);
 7489        let position = point_for_position.previous_valid;
 7490
 7491        self.select(
 7492            SelectPhase::BeginColumnar {
 7493                position,
 7494                reset: false,
 7495                mode,
 7496                goal_column: point_for_position.exact_unclipped.column(),
 7497            },
 7498            window,
 7499            cx,
 7500        );
 7501    }
 7502
 7503    fn update_edit_prediction_preview(
 7504        &mut self,
 7505        modifiers: &Modifiers,
 7506        window: &mut Window,
 7507        cx: &mut Context<Self>,
 7508    ) {
 7509        let mut modifiers_held = false;
 7510        if let Some(accept_keystroke) = self
 7511            .accept_edit_prediction_keybind(false, window, cx)
 7512            .keystroke()
 7513        {
 7514            modifiers_held = modifiers_held
 7515                || (&accept_keystroke.modifiers == modifiers
 7516                    && accept_keystroke.modifiers.modified());
 7517        };
 7518        if let Some(accept_partial_keystroke) = self
 7519            .accept_edit_prediction_keybind(true, window, cx)
 7520            .keystroke()
 7521        {
 7522            modifiers_held = modifiers_held
 7523                || (&accept_partial_keystroke.modifiers == modifiers
 7524                    && accept_partial_keystroke.modifiers.modified());
 7525        }
 7526
 7527        if modifiers_held {
 7528            if matches!(
 7529                self.edit_prediction_preview,
 7530                EditPredictionPreview::Inactive { .. }
 7531            ) {
 7532                self.edit_prediction_preview = EditPredictionPreview::Active {
 7533                    previous_scroll_position: None,
 7534                    since: Instant::now(),
 7535                };
 7536
 7537                self.update_visible_inline_completion(window, cx);
 7538                cx.notify();
 7539            }
 7540        } else if let EditPredictionPreview::Active {
 7541            previous_scroll_position,
 7542            since,
 7543        } = self.edit_prediction_preview
 7544        {
 7545            if let (Some(previous_scroll_position), Some(position_map)) =
 7546                (previous_scroll_position, self.last_position_map.as_ref())
 7547            {
 7548                self.set_scroll_position(
 7549                    previous_scroll_position
 7550                        .scroll_position(&position_map.snapshot.display_snapshot),
 7551                    window,
 7552                    cx,
 7553                );
 7554            }
 7555
 7556            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7557                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7558            };
 7559            self.clear_row_highlights::<EditPredictionPreview>();
 7560            self.update_visible_inline_completion(window, cx);
 7561            cx.notify();
 7562        }
 7563    }
 7564
 7565    fn update_visible_inline_completion(
 7566        &mut self,
 7567        _window: &mut Window,
 7568        cx: &mut Context<Self>,
 7569    ) -> Option<()> {
 7570        let selection = self.selections.newest_anchor();
 7571        let cursor = selection.head();
 7572        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7573        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7574        let excerpt_id = cursor.excerpt_id;
 7575
 7576        let show_in_menu = self.show_edit_predictions_in_menu();
 7577        let completions_menu_has_precedence = !show_in_menu
 7578            && (self.context_menu.borrow().is_some()
 7579                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7580
 7581        if completions_menu_has_precedence
 7582            || !offset_selection.is_empty()
 7583            || self
 7584                .active_inline_completion
 7585                .as_ref()
 7586                .map_or(false, |completion| {
 7587                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7588                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7589                    !invalidation_range.contains(&offset_selection.head())
 7590                })
 7591        {
 7592            self.discard_inline_completion(false, cx);
 7593            return None;
 7594        }
 7595
 7596        self.take_active_inline_completion(cx);
 7597        let Some(provider) = self.edit_prediction_provider() else {
 7598            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7599            return None;
 7600        };
 7601
 7602        let (buffer, cursor_buffer_position) =
 7603            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7604
 7605        self.edit_prediction_settings =
 7606            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7607
 7608        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7609
 7610        if self.edit_prediction_indent_conflict {
 7611            let cursor_point = cursor.to_point(&multibuffer);
 7612
 7613            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7614
 7615            if let Some((_, indent)) = indents.iter().next() {
 7616                if indent.len == cursor_point.column {
 7617                    self.edit_prediction_indent_conflict = false;
 7618                }
 7619            }
 7620        }
 7621
 7622        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7623        let edits = inline_completion
 7624            .edits
 7625            .into_iter()
 7626            .flat_map(|(range, new_text)| {
 7627                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7628                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7629                Some((start..end, new_text))
 7630            })
 7631            .collect::<Vec<_>>();
 7632        if edits.is_empty() {
 7633            return None;
 7634        }
 7635
 7636        let first_edit_start = edits.first().unwrap().0.start;
 7637        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7638        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7639
 7640        let last_edit_end = edits.last().unwrap().0.end;
 7641        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7642        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7643
 7644        let cursor_row = cursor.to_point(&multibuffer).row;
 7645
 7646        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7647
 7648        let mut inlay_ids = Vec::new();
 7649        let invalidation_row_range;
 7650        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7651            Some(cursor_row..edit_end_row)
 7652        } else if cursor_row > edit_end_row {
 7653            Some(edit_start_row..cursor_row)
 7654        } else {
 7655            None
 7656        };
 7657        let is_move =
 7658            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7659        let completion = if is_move {
 7660            invalidation_row_range =
 7661                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7662            let target = first_edit_start;
 7663            InlineCompletion::Move { target, snapshot }
 7664        } else {
 7665            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7666                && !self.inline_completions_hidden_for_vim_mode;
 7667
 7668            if show_completions_in_buffer {
 7669                if edits
 7670                    .iter()
 7671                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7672                {
 7673                    let mut inlays = Vec::new();
 7674                    for (range, new_text) in &edits {
 7675                        let inlay = Inlay::inline_completion(
 7676                            post_inc(&mut self.next_inlay_id),
 7677                            range.start,
 7678                            new_text.as_str(),
 7679                        );
 7680                        inlay_ids.push(inlay.id);
 7681                        inlays.push(inlay);
 7682                    }
 7683
 7684                    self.splice_inlays(&[], inlays, cx);
 7685                } else {
 7686                    let background_color = cx.theme().status().deleted_background;
 7687                    self.highlight_text::<InlineCompletionHighlight>(
 7688                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7689                        HighlightStyle {
 7690                            background_color: Some(background_color),
 7691                            ..Default::default()
 7692                        },
 7693                        cx,
 7694                    );
 7695                }
 7696            }
 7697
 7698            invalidation_row_range = edit_start_row..edit_end_row;
 7699
 7700            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7701                if provider.show_tab_accept_marker() {
 7702                    EditDisplayMode::TabAccept
 7703                } else {
 7704                    EditDisplayMode::Inline
 7705                }
 7706            } else {
 7707                EditDisplayMode::DiffPopover
 7708            };
 7709
 7710            InlineCompletion::Edit {
 7711                edits,
 7712                edit_preview: inline_completion.edit_preview,
 7713                display_mode,
 7714                snapshot,
 7715            }
 7716        };
 7717
 7718        let invalidation_range = multibuffer
 7719            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7720            ..multibuffer.anchor_after(Point::new(
 7721                invalidation_row_range.end,
 7722                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7723            ));
 7724
 7725        self.stale_inline_completion_in_menu = None;
 7726        self.active_inline_completion = Some(InlineCompletionState {
 7727            inlay_ids,
 7728            completion,
 7729            completion_id: inline_completion.id,
 7730            invalidation_range,
 7731        });
 7732
 7733        cx.notify();
 7734
 7735        Some(())
 7736    }
 7737
 7738    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7739        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7740    }
 7741
 7742    fn clear_tasks(&mut self) {
 7743        self.tasks.clear()
 7744    }
 7745
 7746    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7747        if self.tasks.insert(key, value).is_some() {
 7748            // This case should hopefully be rare, but just in case...
 7749            log::error!(
 7750                "multiple different run targets found on a single line, only the last target will be rendered"
 7751            )
 7752        }
 7753    }
 7754
 7755    /// Get all display points of breakpoints that will be rendered within editor
 7756    ///
 7757    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7758    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7759    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7760    fn active_breakpoints(
 7761        &self,
 7762        range: Range<DisplayRow>,
 7763        window: &mut Window,
 7764        cx: &mut Context<Self>,
 7765    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7766        let mut breakpoint_display_points = HashMap::default();
 7767
 7768        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7769            return breakpoint_display_points;
 7770        };
 7771
 7772        let snapshot = self.snapshot(window, cx);
 7773
 7774        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7775        let Some(project) = self.project.as_ref() else {
 7776            return breakpoint_display_points;
 7777        };
 7778
 7779        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7780            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7781
 7782        for (buffer_snapshot, range, excerpt_id) in
 7783            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7784        {
 7785            let Some(buffer) = project
 7786                .read(cx)
 7787                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7788            else {
 7789                continue;
 7790            };
 7791            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7792                &buffer,
 7793                Some(
 7794                    buffer_snapshot.anchor_before(range.start)
 7795                        ..buffer_snapshot.anchor_after(range.end),
 7796                ),
 7797                buffer_snapshot,
 7798                cx,
 7799            );
 7800            for (breakpoint, state) in breakpoints {
 7801                let multi_buffer_anchor =
 7802                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7803                let position = multi_buffer_anchor
 7804                    .to_point(&multi_buffer_snapshot)
 7805                    .to_display_point(&snapshot);
 7806
 7807                breakpoint_display_points.insert(
 7808                    position.row(),
 7809                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7810                );
 7811            }
 7812        }
 7813
 7814        breakpoint_display_points
 7815    }
 7816
 7817    fn breakpoint_context_menu(
 7818        &self,
 7819        anchor: Anchor,
 7820        window: &mut Window,
 7821        cx: &mut Context<Self>,
 7822    ) -> Entity<ui::ContextMenu> {
 7823        let weak_editor = cx.weak_entity();
 7824        let focus_handle = self.focus_handle(cx);
 7825
 7826        let row = self
 7827            .buffer
 7828            .read(cx)
 7829            .snapshot(cx)
 7830            .summary_for_anchor::<Point>(&anchor)
 7831            .row;
 7832
 7833        let breakpoint = self
 7834            .breakpoint_at_row(row, window, cx)
 7835            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7836
 7837        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7838            "Edit Log Breakpoint"
 7839        } else {
 7840            "Set Log Breakpoint"
 7841        };
 7842
 7843        let condition_breakpoint_msg = if breakpoint
 7844            .as_ref()
 7845            .is_some_and(|bp| bp.1.condition.is_some())
 7846        {
 7847            "Edit Condition Breakpoint"
 7848        } else {
 7849            "Set Condition Breakpoint"
 7850        };
 7851
 7852        let hit_condition_breakpoint_msg = if breakpoint
 7853            .as_ref()
 7854            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7855        {
 7856            "Edit Hit Condition Breakpoint"
 7857        } else {
 7858            "Set Hit Condition Breakpoint"
 7859        };
 7860
 7861        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7862            "Unset Breakpoint"
 7863        } else {
 7864            "Set Breakpoint"
 7865        };
 7866
 7867        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7868
 7869        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7870            BreakpointState::Enabled => Some("Disable"),
 7871            BreakpointState::Disabled => Some("Enable"),
 7872        });
 7873
 7874        let (anchor, breakpoint) =
 7875            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7876
 7877        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7878            menu.on_blur_subscription(Subscription::new(|| {}))
 7879                .context(focus_handle)
 7880                .when(run_to_cursor, |this| {
 7881                    let weak_editor = weak_editor.clone();
 7882                    this.entry("Run to cursor", None, move |window, cx| {
 7883                        weak_editor
 7884                            .update(cx, |editor, cx| {
 7885                                editor.change_selections(
 7886                                    SelectionEffects::no_scroll(),
 7887                                    window,
 7888                                    cx,
 7889                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7890                                );
 7891                            })
 7892                            .ok();
 7893
 7894                        window.dispatch_action(Box::new(RunToCursor), cx);
 7895                    })
 7896                    .separator()
 7897                })
 7898                .when_some(toggle_state_msg, |this, msg| {
 7899                    this.entry(msg, None, {
 7900                        let weak_editor = weak_editor.clone();
 7901                        let breakpoint = breakpoint.clone();
 7902                        move |_window, cx| {
 7903                            weak_editor
 7904                                .update(cx, |this, cx| {
 7905                                    this.edit_breakpoint_at_anchor(
 7906                                        anchor,
 7907                                        breakpoint.as_ref().clone(),
 7908                                        BreakpointEditAction::InvertState,
 7909                                        cx,
 7910                                    );
 7911                                })
 7912                                .log_err();
 7913                        }
 7914                    })
 7915                })
 7916                .entry(set_breakpoint_msg, None, {
 7917                    let weak_editor = weak_editor.clone();
 7918                    let breakpoint = breakpoint.clone();
 7919                    move |_window, cx| {
 7920                        weak_editor
 7921                            .update(cx, |this, cx| {
 7922                                this.edit_breakpoint_at_anchor(
 7923                                    anchor,
 7924                                    breakpoint.as_ref().clone(),
 7925                                    BreakpointEditAction::Toggle,
 7926                                    cx,
 7927                                );
 7928                            })
 7929                            .log_err();
 7930                    }
 7931                })
 7932                .entry(log_breakpoint_msg, None, {
 7933                    let breakpoint = breakpoint.clone();
 7934                    let weak_editor = weak_editor.clone();
 7935                    move |window, cx| {
 7936                        weak_editor
 7937                            .update(cx, |this, cx| {
 7938                                this.add_edit_breakpoint_block(
 7939                                    anchor,
 7940                                    breakpoint.as_ref(),
 7941                                    BreakpointPromptEditAction::Log,
 7942                                    window,
 7943                                    cx,
 7944                                );
 7945                            })
 7946                            .log_err();
 7947                    }
 7948                })
 7949                .entry(condition_breakpoint_msg, None, {
 7950                    let breakpoint = breakpoint.clone();
 7951                    let weak_editor = weak_editor.clone();
 7952                    move |window, cx| {
 7953                        weak_editor
 7954                            .update(cx, |this, cx| {
 7955                                this.add_edit_breakpoint_block(
 7956                                    anchor,
 7957                                    breakpoint.as_ref(),
 7958                                    BreakpointPromptEditAction::Condition,
 7959                                    window,
 7960                                    cx,
 7961                                );
 7962                            })
 7963                            .log_err();
 7964                    }
 7965                })
 7966                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7967                    weak_editor
 7968                        .update(cx, |this, cx| {
 7969                            this.add_edit_breakpoint_block(
 7970                                anchor,
 7971                                breakpoint.as_ref(),
 7972                                BreakpointPromptEditAction::HitCondition,
 7973                                window,
 7974                                cx,
 7975                            );
 7976                        })
 7977                        .log_err();
 7978                })
 7979        })
 7980    }
 7981
 7982    fn render_breakpoint(
 7983        &self,
 7984        position: Anchor,
 7985        row: DisplayRow,
 7986        breakpoint: &Breakpoint,
 7987        state: Option<BreakpointSessionState>,
 7988        cx: &mut Context<Self>,
 7989    ) -> IconButton {
 7990        let is_rejected = state.is_some_and(|s| !s.verified);
 7991        // Is it a breakpoint that shows up when hovering over gutter?
 7992        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7993            (false, false),
 7994            |PhantomBreakpointIndicator {
 7995                 is_active,
 7996                 display_row,
 7997                 collides_with_existing_breakpoint,
 7998             }| {
 7999                (
 8000                    is_active && display_row == row,
 8001                    collides_with_existing_breakpoint,
 8002                )
 8003            },
 8004        );
 8005
 8006        let (color, icon) = {
 8007            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8008                (false, false) => ui::IconName::DebugBreakpoint,
 8009                (true, false) => ui::IconName::DebugLogBreakpoint,
 8010                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8011                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8012            };
 8013
 8014            let color = if is_phantom {
 8015                Color::Hint
 8016            } else if is_rejected {
 8017                Color::Disabled
 8018            } else {
 8019                Color::Debugger
 8020            };
 8021
 8022            (color, icon)
 8023        };
 8024
 8025        let breakpoint = Arc::from(breakpoint.clone());
 8026
 8027        let alt_as_text = gpui::Keystroke {
 8028            modifiers: Modifiers::secondary_key(),
 8029            ..Default::default()
 8030        };
 8031        let primary_action_text = if breakpoint.is_disabled() {
 8032            "Enable breakpoint"
 8033        } else if is_phantom && !collides_with_existing {
 8034            "Set breakpoint"
 8035        } else {
 8036            "Unset breakpoint"
 8037        };
 8038        let focus_handle = self.focus_handle.clone();
 8039
 8040        let meta = if is_rejected {
 8041            SharedString::from("No executable code is associated with this line.")
 8042        } else if collides_with_existing && !breakpoint.is_disabled() {
 8043            SharedString::from(format!(
 8044                "{alt_as_text}-click to disable,\nright-click for more options."
 8045            ))
 8046        } else {
 8047            SharedString::from("Right-click for more options.")
 8048        };
 8049        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8050            .icon_size(IconSize::XSmall)
 8051            .size(ui::ButtonSize::None)
 8052            .when(is_rejected, |this| {
 8053                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8054            })
 8055            .icon_color(color)
 8056            .style(ButtonStyle::Transparent)
 8057            .on_click(cx.listener({
 8058                let breakpoint = breakpoint.clone();
 8059
 8060                move |editor, event: &ClickEvent, window, cx| {
 8061                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8062                        BreakpointEditAction::InvertState
 8063                    } else {
 8064                        BreakpointEditAction::Toggle
 8065                    };
 8066
 8067                    window.focus(&editor.focus_handle(cx));
 8068                    editor.edit_breakpoint_at_anchor(
 8069                        position,
 8070                        breakpoint.as_ref().clone(),
 8071                        edit_action,
 8072                        cx,
 8073                    );
 8074                }
 8075            }))
 8076            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8077                editor.set_breakpoint_context_menu(
 8078                    row,
 8079                    Some(position),
 8080                    event.down.position,
 8081                    window,
 8082                    cx,
 8083                );
 8084            }))
 8085            .tooltip(move |window, cx| {
 8086                Tooltip::with_meta_in(
 8087                    primary_action_text,
 8088                    Some(&ToggleBreakpoint),
 8089                    meta.clone(),
 8090                    &focus_handle,
 8091                    window,
 8092                    cx,
 8093                )
 8094            })
 8095    }
 8096
 8097    fn build_tasks_context(
 8098        project: &Entity<Project>,
 8099        buffer: &Entity<Buffer>,
 8100        buffer_row: u32,
 8101        tasks: &Arc<RunnableTasks>,
 8102        cx: &mut Context<Self>,
 8103    ) -> Task<Option<task::TaskContext>> {
 8104        let position = Point::new(buffer_row, tasks.column);
 8105        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8106        let location = Location {
 8107            buffer: buffer.clone(),
 8108            range: range_start..range_start,
 8109        };
 8110        // Fill in the environmental variables from the tree-sitter captures
 8111        let mut captured_task_variables = TaskVariables::default();
 8112        for (capture_name, value) in tasks.extra_variables.clone() {
 8113            captured_task_variables.insert(
 8114                task::VariableName::Custom(capture_name.into()),
 8115                value.clone(),
 8116            );
 8117        }
 8118        project.update(cx, |project, cx| {
 8119            project.task_store().update(cx, |task_store, cx| {
 8120                task_store.task_context_for_location(captured_task_variables, location, cx)
 8121            })
 8122        })
 8123    }
 8124
 8125    pub fn spawn_nearest_task(
 8126        &mut self,
 8127        action: &SpawnNearestTask,
 8128        window: &mut Window,
 8129        cx: &mut Context<Self>,
 8130    ) {
 8131        let Some((workspace, _)) = self.workspace.clone() else {
 8132            return;
 8133        };
 8134        let Some(project) = self.project.clone() else {
 8135            return;
 8136        };
 8137
 8138        // Try to find a closest, enclosing node using tree-sitter that has a
 8139        // task
 8140        let Some((buffer, buffer_row, tasks)) = self
 8141            .find_enclosing_node_task(cx)
 8142            // Or find the task that's closest in row-distance.
 8143            .or_else(|| self.find_closest_task(cx))
 8144        else {
 8145            return;
 8146        };
 8147
 8148        let reveal_strategy = action.reveal;
 8149        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8150        cx.spawn_in(window, async move |_, cx| {
 8151            let context = task_context.await?;
 8152            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8153
 8154            let resolved = &mut resolved_task.resolved;
 8155            resolved.reveal = reveal_strategy;
 8156
 8157            workspace
 8158                .update_in(cx, |workspace, window, cx| {
 8159                    workspace.schedule_resolved_task(
 8160                        task_source_kind,
 8161                        resolved_task,
 8162                        false,
 8163                        window,
 8164                        cx,
 8165                    );
 8166                })
 8167                .ok()
 8168        })
 8169        .detach();
 8170    }
 8171
 8172    fn find_closest_task(
 8173        &mut self,
 8174        cx: &mut Context<Self>,
 8175    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8176        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8177
 8178        let ((buffer_id, row), tasks) = self
 8179            .tasks
 8180            .iter()
 8181            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8182
 8183        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8184        let tasks = Arc::new(tasks.to_owned());
 8185        Some((buffer, *row, tasks))
 8186    }
 8187
 8188    fn find_enclosing_node_task(
 8189        &mut self,
 8190        cx: &mut Context<Self>,
 8191    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8192        let snapshot = self.buffer.read(cx).snapshot(cx);
 8193        let offset = self.selections.newest::<usize>(cx).head();
 8194        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8195        let buffer_id = excerpt.buffer().remote_id();
 8196
 8197        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8198        let mut cursor = layer.node().walk();
 8199
 8200        while cursor.goto_first_child_for_byte(offset).is_some() {
 8201            if cursor.node().end_byte() == offset {
 8202                cursor.goto_next_sibling();
 8203            }
 8204        }
 8205
 8206        // Ascend to the smallest ancestor that contains the range and has a task.
 8207        loop {
 8208            let node = cursor.node();
 8209            let node_range = node.byte_range();
 8210            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8211
 8212            // Check if this node contains our offset
 8213            if node_range.start <= offset && node_range.end >= offset {
 8214                // If it contains offset, check for task
 8215                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8216                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8217                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8218                }
 8219            }
 8220
 8221            if !cursor.goto_parent() {
 8222                break;
 8223            }
 8224        }
 8225        None
 8226    }
 8227
 8228    fn render_run_indicator(
 8229        &self,
 8230        _style: &EditorStyle,
 8231        is_active: bool,
 8232        row: DisplayRow,
 8233        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8234        cx: &mut Context<Self>,
 8235    ) -> IconButton {
 8236        let color = Color::Muted;
 8237        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8238
 8239        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8240            .shape(ui::IconButtonShape::Square)
 8241            .icon_size(IconSize::XSmall)
 8242            .icon_color(color)
 8243            .toggle_state(is_active)
 8244            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8245                let quick_launch = e.down.button == MouseButton::Left;
 8246                window.focus(&editor.focus_handle(cx));
 8247                editor.toggle_code_actions(
 8248                    &ToggleCodeActions {
 8249                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8250                        quick_launch,
 8251                    },
 8252                    window,
 8253                    cx,
 8254                );
 8255            }))
 8256            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8257                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8258            }))
 8259    }
 8260
 8261    pub fn context_menu_visible(&self) -> bool {
 8262        !self.edit_prediction_preview_is_active()
 8263            && self
 8264                .context_menu
 8265                .borrow()
 8266                .as_ref()
 8267                .map_or(false, |menu| menu.visible())
 8268    }
 8269
 8270    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8271        self.context_menu
 8272            .borrow()
 8273            .as_ref()
 8274            .map(|menu| menu.origin())
 8275    }
 8276
 8277    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8278        self.context_menu_options = Some(options);
 8279    }
 8280
 8281    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8282    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8283
 8284    fn render_edit_prediction_popover(
 8285        &mut self,
 8286        text_bounds: &Bounds<Pixels>,
 8287        content_origin: gpui::Point<Pixels>,
 8288        right_margin: Pixels,
 8289        editor_snapshot: &EditorSnapshot,
 8290        visible_row_range: Range<DisplayRow>,
 8291        scroll_top: f32,
 8292        scroll_bottom: f32,
 8293        line_layouts: &[LineWithInvisibles],
 8294        line_height: Pixels,
 8295        scroll_pixel_position: gpui::Point<Pixels>,
 8296        newest_selection_head: Option<DisplayPoint>,
 8297        editor_width: Pixels,
 8298        style: &EditorStyle,
 8299        window: &mut Window,
 8300        cx: &mut App,
 8301    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8302        if self.mode().is_minimap() {
 8303            return None;
 8304        }
 8305        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8306
 8307        if self.edit_prediction_visible_in_cursor_popover(true) {
 8308            return None;
 8309        }
 8310
 8311        match &active_inline_completion.completion {
 8312            InlineCompletion::Move { target, .. } => {
 8313                let target_display_point = target.to_display_point(editor_snapshot);
 8314
 8315                if self.edit_prediction_requires_modifier() {
 8316                    if !self.edit_prediction_preview_is_active() {
 8317                        return None;
 8318                    }
 8319
 8320                    self.render_edit_prediction_modifier_jump_popover(
 8321                        text_bounds,
 8322                        content_origin,
 8323                        visible_row_range,
 8324                        line_layouts,
 8325                        line_height,
 8326                        scroll_pixel_position,
 8327                        newest_selection_head,
 8328                        target_display_point,
 8329                        window,
 8330                        cx,
 8331                    )
 8332                } else {
 8333                    self.render_edit_prediction_eager_jump_popover(
 8334                        text_bounds,
 8335                        content_origin,
 8336                        editor_snapshot,
 8337                        visible_row_range,
 8338                        scroll_top,
 8339                        scroll_bottom,
 8340                        line_height,
 8341                        scroll_pixel_position,
 8342                        target_display_point,
 8343                        editor_width,
 8344                        window,
 8345                        cx,
 8346                    )
 8347                }
 8348            }
 8349            InlineCompletion::Edit {
 8350                display_mode: EditDisplayMode::Inline,
 8351                ..
 8352            } => None,
 8353            InlineCompletion::Edit {
 8354                display_mode: EditDisplayMode::TabAccept,
 8355                edits,
 8356                ..
 8357            } => {
 8358                let range = &edits.first()?.0;
 8359                let target_display_point = range.end.to_display_point(editor_snapshot);
 8360
 8361                self.render_edit_prediction_end_of_line_popover(
 8362                    "Accept",
 8363                    editor_snapshot,
 8364                    visible_row_range,
 8365                    target_display_point,
 8366                    line_height,
 8367                    scroll_pixel_position,
 8368                    content_origin,
 8369                    editor_width,
 8370                    window,
 8371                    cx,
 8372                )
 8373            }
 8374            InlineCompletion::Edit {
 8375                edits,
 8376                edit_preview,
 8377                display_mode: EditDisplayMode::DiffPopover,
 8378                snapshot,
 8379            } => self.render_edit_prediction_diff_popover(
 8380                text_bounds,
 8381                content_origin,
 8382                right_margin,
 8383                editor_snapshot,
 8384                visible_row_range,
 8385                line_layouts,
 8386                line_height,
 8387                scroll_pixel_position,
 8388                newest_selection_head,
 8389                editor_width,
 8390                style,
 8391                edits,
 8392                edit_preview,
 8393                snapshot,
 8394                window,
 8395                cx,
 8396            ),
 8397        }
 8398    }
 8399
 8400    fn render_edit_prediction_modifier_jump_popover(
 8401        &mut self,
 8402        text_bounds: &Bounds<Pixels>,
 8403        content_origin: gpui::Point<Pixels>,
 8404        visible_row_range: Range<DisplayRow>,
 8405        line_layouts: &[LineWithInvisibles],
 8406        line_height: Pixels,
 8407        scroll_pixel_position: gpui::Point<Pixels>,
 8408        newest_selection_head: Option<DisplayPoint>,
 8409        target_display_point: DisplayPoint,
 8410        window: &mut Window,
 8411        cx: &mut App,
 8412    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8413        let scrolled_content_origin =
 8414            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8415
 8416        const SCROLL_PADDING_Y: Pixels = px(12.);
 8417
 8418        if target_display_point.row() < visible_row_range.start {
 8419            return self.render_edit_prediction_scroll_popover(
 8420                |_| SCROLL_PADDING_Y,
 8421                IconName::ArrowUp,
 8422                visible_row_range,
 8423                line_layouts,
 8424                newest_selection_head,
 8425                scrolled_content_origin,
 8426                window,
 8427                cx,
 8428            );
 8429        } else if target_display_point.row() >= visible_row_range.end {
 8430            return self.render_edit_prediction_scroll_popover(
 8431                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8432                IconName::ArrowDown,
 8433                visible_row_range,
 8434                line_layouts,
 8435                newest_selection_head,
 8436                scrolled_content_origin,
 8437                window,
 8438                cx,
 8439            );
 8440        }
 8441
 8442        const POLE_WIDTH: Pixels = px(2.);
 8443
 8444        let line_layout =
 8445            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8446        let target_column = target_display_point.column() as usize;
 8447
 8448        let target_x = line_layout.x_for_index(target_column);
 8449        let target_y =
 8450            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8451
 8452        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8453
 8454        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8455        border_color.l += 0.001;
 8456
 8457        let mut element = v_flex()
 8458            .items_end()
 8459            .when(flag_on_right, |el| el.items_start())
 8460            .child(if flag_on_right {
 8461                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8462                    .rounded_bl(px(0.))
 8463                    .rounded_tl(px(0.))
 8464                    .border_l_2()
 8465                    .border_color(border_color)
 8466            } else {
 8467                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8468                    .rounded_br(px(0.))
 8469                    .rounded_tr(px(0.))
 8470                    .border_r_2()
 8471                    .border_color(border_color)
 8472            })
 8473            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8474            .into_any();
 8475
 8476        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8477
 8478        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8479            - point(
 8480                if flag_on_right {
 8481                    POLE_WIDTH
 8482                } else {
 8483                    size.width - POLE_WIDTH
 8484                },
 8485                size.height - line_height,
 8486            );
 8487
 8488        origin.x = origin.x.max(content_origin.x);
 8489
 8490        element.prepaint_at(origin, window, cx);
 8491
 8492        Some((element, origin))
 8493    }
 8494
 8495    fn render_edit_prediction_scroll_popover(
 8496        &mut self,
 8497        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8498        scroll_icon: IconName,
 8499        visible_row_range: Range<DisplayRow>,
 8500        line_layouts: &[LineWithInvisibles],
 8501        newest_selection_head: Option<DisplayPoint>,
 8502        scrolled_content_origin: gpui::Point<Pixels>,
 8503        window: &mut Window,
 8504        cx: &mut App,
 8505    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8506        let mut element = self
 8507            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8508            .into_any();
 8509
 8510        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8511
 8512        let cursor = newest_selection_head?;
 8513        let cursor_row_layout =
 8514            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8515        let cursor_column = cursor.column() as usize;
 8516
 8517        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8518
 8519        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8520
 8521        element.prepaint_at(origin, window, cx);
 8522        Some((element, origin))
 8523    }
 8524
 8525    fn render_edit_prediction_eager_jump_popover(
 8526        &mut self,
 8527        text_bounds: &Bounds<Pixels>,
 8528        content_origin: gpui::Point<Pixels>,
 8529        editor_snapshot: &EditorSnapshot,
 8530        visible_row_range: Range<DisplayRow>,
 8531        scroll_top: f32,
 8532        scroll_bottom: f32,
 8533        line_height: Pixels,
 8534        scroll_pixel_position: gpui::Point<Pixels>,
 8535        target_display_point: DisplayPoint,
 8536        editor_width: Pixels,
 8537        window: &mut Window,
 8538        cx: &mut App,
 8539    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8540        if target_display_point.row().as_f32() < scroll_top {
 8541            let mut element = self
 8542                .render_edit_prediction_line_popover(
 8543                    "Jump to Edit",
 8544                    Some(IconName::ArrowUp),
 8545                    window,
 8546                    cx,
 8547                )?
 8548                .into_any();
 8549
 8550            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8551            let offset = point(
 8552                (text_bounds.size.width - size.width) / 2.,
 8553                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8554            );
 8555
 8556            let origin = text_bounds.origin + offset;
 8557            element.prepaint_at(origin, window, cx);
 8558            Some((element, origin))
 8559        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8560            let mut element = self
 8561                .render_edit_prediction_line_popover(
 8562                    "Jump to Edit",
 8563                    Some(IconName::ArrowDown),
 8564                    window,
 8565                    cx,
 8566                )?
 8567                .into_any();
 8568
 8569            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8570            let offset = point(
 8571                (text_bounds.size.width - size.width) / 2.,
 8572                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8573            );
 8574
 8575            let origin = text_bounds.origin + offset;
 8576            element.prepaint_at(origin, window, cx);
 8577            Some((element, origin))
 8578        } else {
 8579            self.render_edit_prediction_end_of_line_popover(
 8580                "Jump to Edit",
 8581                editor_snapshot,
 8582                visible_row_range,
 8583                target_display_point,
 8584                line_height,
 8585                scroll_pixel_position,
 8586                content_origin,
 8587                editor_width,
 8588                window,
 8589                cx,
 8590            )
 8591        }
 8592    }
 8593
 8594    fn render_edit_prediction_end_of_line_popover(
 8595        self: &mut Editor,
 8596        label: &'static str,
 8597        editor_snapshot: &EditorSnapshot,
 8598        visible_row_range: Range<DisplayRow>,
 8599        target_display_point: DisplayPoint,
 8600        line_height: Pixels,
 8601        scroll_pixel_position: gpui::Point<Pixels>,
 8602        content_origin: gpui::Point<Pixels>,
 8603        editor_width: Pixels,
 8604        window: &mut Window,
 8605        cx: &mut App,
 8606    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8607        let target_line_end = DisplayPoint::new(
 8608            target_display_point.row(),
 8609            editor_snapshot.line_len(target_display_point.row()),
 8610        );
 8611
 8612        let mut element = self
 8613            .render_edit_prediction_line_popover(label, None, window, cx)?
 8614            .into_any();
 8615
 8616        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8617
 8618        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8619
 8620        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8621        let mut origin = start_point
 8622            + line_origin
 8623            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8624        origin.x = origin.x.max(content_origin.x);
 8625
 8626        let max_x = content_origin.x + editor_width - size.width;
 8627
 8628        if origin.x > max_x {
 8629            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8630
 8631            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8632                origin.y += offset;
 8633                IconName::ArrowUp
 8634            } else {
 8635                origin.y -= offset;
 8636                IconName::ArrowDown
 8637            };
 8638
 8639            element = self
 8640                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8641                .into_any();
 8642
 8643            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8644
 8645            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8646        }
 8647
 8648        element.prepaint_at(origin, window, cx);
 8649        Some((element, origin))
 8650    }
 8651
 8652    fn render_edit_prediction_diff_popover(
 8653        self: &Editor,
 8654        text_bounds: &Bounds<Pixels>,
 8655        content_origin: gpui::Point<Pixels>,
 8656        right_margin: Pixels,
 8657        editor_snapshot: &EditorSnapshot,
 8658        visible_row_range: Range<DisplayRow>,
 8659        line_layouts: &[LineWithInvisibles],
 8660        line_height: Pixels,
 8661        scroll_pixel_position: gpui::Point<Pixels>,
 8662        newest_selection_head: Option<DisplayPoint>,
 8663        editor_width: Pixels,
 8664        style: &EditorStyle,
 8665        edits: &Vec<(Range<Anchor>, String)>,
 8666        edit_preview: &Option<language::EditPreview>,
 8667        snapshot: &language::BufferSnapshot,
 8668        window: &mut Window,
 8669        cx: &mut App,
 8670    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8671        let edit_start = edits
 8672            .first()
 8673            .unwrap()
 8674            .0
 8675            .start
 8676            .to_display_point(editor_snapshot);
 8677        let edit_end = edits
 8678            .last()
 8679            .unwrap()
 8680            .0
 8681            .end
 8682            .to_display_point(editor_snapshot);
 8683
 8684        let is_visible = visible_row_range.contains(&edit_start.row())
 8685            || visible_row_range.contains(&edit_end.row());
 8686        if !is_visible {
 8687            return None;
 8688        }
 8689
 8690        let highlighted_edits =
 8691            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8692
 8693        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8694        let line_count = highlighted_edits.text.lines().count();
 8695
 8696        const BORDER_WIDTH: Pixels = px(1.);
 8697
 8698        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8699        let has_keybind = keybind.is_some();
 8700
 8701        let mut element = h_flex()
 8702            .items_start()
 8703            .child(
 8704                h_flex()
 8705                    .bg(cx.theme().colors().editor_background)
 8706                    .border(BORDER_WIDTH)
 8707                    .shadow_sm()
 8708                    .border_color(cx.theme().colors().border)
 8709                    .rounded_l_lg()
 8710                    .when(line_count > 1, |el| el.rounded_br_lg())
 8711                    .pr_1()
 8712                    .child(styled_text),
 8713            )
 8714            .child(
 8715                h_flex()
 8716                    .h(line_height + BORDER_WIDTH * 2.)
 8717                    .px_1p5()
 8718                    .gap_1()
 8719                    // Workaround: For some reason, there's a gap if we don't do this
 8720                    .ml(-BORDER_WIDTH)
 8721                    .shadow(vec![gpui::BoxShadow {
 8722                        color: gpui::black().opacity(0.05),
 8723                        offset: point(px(1.), px(1.)),
 8724                        blur_radius: px(2.),
 8725                        spread_radius: px(0.),
 8726                    }])
 8727                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8728                    .border(BORDER_WIDTH)
 8729                    .border_color(cx.theme().colors().border)
 8730                    .rounded_r_lg()
 8731                    .id("edit_prediction_diff_popover_keybind")
 8732                    .when(!has_keybind, |el| {
 8733                        let status_colors = cx.theme().status();
 8734
 8735                        el.bg(status_colors.error_background)
 8736                            .border_color(status_colors.error.opacity(0.6))
 8737                            .child(Icon::new(IconName::Info).color(Color::Error))
 8738                            .cursor_default()
 8739                            .hoverable_tooltip(move |_window, cx| {
 8740                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8741                            })
 8742                    })
 8743                    .children(keybind),
 8744            )
 8745            .into_any();
 8746
 8747        let longest_row =
 8748            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8749        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8750            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8751        } else {
 8752            layout_line(
 8753                longest_row,
 8754                editor_snapshot,
 8755                style,
 8756                editor_width,
 8757                |_| false,
 8758                window,
 8759                cx,
 8760            )
 8761            .width
 8762        };
 8763
 8764        let viewport_bounds =
 8765            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8766                right: -right_margin,
 8767                ..Default::default()
 8768            });
 8769
 8770        let x_after_longest =
 8771            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8772                - scroll_pixel_position.x;
 8773
 8774        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8775
 8776        // Fully visible if it can be displayed within the window (allow overlapping other
 8777        // panes). However, this is only allowed if the popover starts within text_bounds.
 8778        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8779            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8780
 8781        let mut origin = if can_position_to_the_right {
 8782            point(
 8783                x_after_longest,
 8784                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8785                    - scroll_pixel_position.y,
 8786            )
 8787        } else {
 8788            let cursor_row = newest_selection_head.map(|head| head.row());
 8789            let above_edit = edit_start
 8790                .row()
 8791                .0
 8792                .checked_sub(line_count as u32)
 8793                .map(DisplayRow);
 8794            let below_edit = Some(edit_end.row() + 1);
 8795            let above_cursor =
 8796                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8797            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8798
 8799            // Place the edit popover adjacent to the edit if there is a location
 8800            // available that is onscreen and does not obscure the cursor. Otherwise,
 8801            // place it adjacent to the cursor.
 8802            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8803                .into_iter()
 8804                .flatten()
 8805                .find(|&start_row| {
 8806                    let end_row = start_row + line_count as u32;
 8807                    visible_row_range.contains(&start_row)
 8808                        && visible_row_range.contains(&end_row)
 8809                        && cursor_row.map_or(true, |cursor_row| {
 8810                            !((start_row..end_row).contains(&cursor_row))
 8811                        })
 8812                })?;
 8813
 8814            content_origin
 8815                + point(
 8816                    -scroll_pixel_position.x,
 8817                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8818                )
 8819        };
 8820
 8821        origin.x -= BORDER_WIDTH;
 8822
 8823        window.defer_draw(element, origin, 1);
 8824
 8825        // Do not return an element, since it will already be drawn due to defer_draw.
 8826        None
 8827    }
 8828
 8829    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8830        px(30.)
 8831    }
 8832
 8833    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8834        if self.read_only(cx) {
 8835            cx.theme().players().read_only()
 8836        } else {
 8837            self.style.as_ref().unwrap().local_player
 8838        }
 8839    }
 8840
 8841    fn render_edit_prediction_accept_keybind(
 8842        &self,
 8843        window: &mut Window,
 8844        cx: &App,
 8845    ) -> Option<AnyElement> {
 8846        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8847        let accept_keystroke = accept_binding.keystroke()?;
 8848
 8849        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8850
 8851        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8852            Color::Accent
 8853        } else {
 8854            Color::Muted
 8855        };
 8856
 8857        h_flex()
 8858            .px_0p5()
 8859            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8860            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8861            .text_size(TextSize::XSmall.rems(cx))
 8862            .child(h_flex().children(ui::render_modifiers(
 8863                &accept_keystroke.modifiers,
 8864                PlatformStyle::platform(),
 8865                Some(modifiers_color),
 8866                Some(IconSize::XSmall.rems().into()),
 8867                true,
 8868            )))
 8869            .when(is_platform_style_mac, |parent| {
 8870                parent.child(accept_keystroke.key.clone())
 8871            })
 8872            .when(!is_platform_style_mac, |parent| {
 8873                parent.child(
 8874                    Key::new(
 8875                        util::capitalize(&accept_keystroke.key),
 8876                        Some(Color::Default),
 8877                    )
 8878                    .size(Some(IconSize::XSmall.rems().into())),
 8879                )
 8880            })
 8881            .into_any()
 8882            .into()
 8883    }
 8884
 8885    fn render_edit_prediction_line_popover(
 8886        &self,
 8887        label: impl Into<SharedString>,
 8888        icon: Option<IconName>,
 8889        window: &mut Window,
 8890        cx: &App,
 8891    ) -> Option<Stateful<Div>> {
 8892        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8893
 8894        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8895        let has_keybind = keybind.is_some();
 8896
 8897        let result = h_flex()
 8898            .id("ep-line-popover")
 8899            .py_0p5()
 8900            .pl_1()
 8901            .pr(padding_right)
 8902            .gap_1()
 8903            .rounded_md()
 8904            .border_1()
 8905            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8906            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8907            .shadow_sm()
 8908            .when(!has_keybind, |el| {
 8909                let status_colors = cx.theme().status();
 8910
 8911                el.bg(status_colors.error_background)
 8912                    .border_color(status_colors.error.opacity(0.6))
 8913                    .pl_2()
 8914                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8915                    .cursor_default()
 8916                    .hoverable_tooltip(move |_window, cx| {
 8917                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8918                    })
 8919            })
 8920            .children(keybind)
 8921            .child(
 8922                Label::new(label)
 8923                    .size(LabelSize::Small)
 8924                    .when(!has_keybind, |el| {
 8925                        el.color(cx.theme().status().error.into()).strikethrough()
 8926                    }),
 8927            )
 8928            .when(!has_keybind, |el| {
 8929                el.child(
 8930                    h_flex().ml_1().child(
 8931                        Icon::new(IconName::Info)
 8932                            .size(IconSize::Small)
 8933                            .color(cx.theme().status().error.into()),
 8934                    ),
 8935                )
 8936            })
 8937            .when_some(icon, |element, icon| {
 8938                element.child(
 8939                    div()
 8940                        .mt(px(1.5))
 8941                        .child(Icon::new(icon).size(IconSize::Small)),
 8942                )
 8943            });
 8944
 8945        Some(result)
 8946    }
 8947
 8948    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8949        let accent_color = cx.theme().colors().text_accent;
 8950        let editor_bg_color = cx.theme().colors().editor_background;
 8951        editor_bg_color.blend(accent_color.opacity(0.1))
 8952    }
 8953
 8954    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8955        let accent_color = cx.theme().colors().text_accent;
 8956        let editor_bg_color = cx.theme().colors().editor_background;
 8957        editor_bg_color.blend(accent_color.opacity(0.6))
 8958    }
 8959
 8960    fn render_edit_prediction_cursor_popover(
 8961        &self,
 8962        min_width: Pixels,
 8963        max_width: Pixels,
 8964        cursor_point: Point,
 8965        style: &EditorStyle,
 8966        accept_keystroke: Option<&gpui::Keystroke>,
 8967        _window: &Window,
 8968        cx: &mut Context<Editor>,
 8969    ) -> Option<AnyElement> {
 8970        let provider = self.edit_prediction_provider.as_ref()?;
 8971
 8972        if provider.provider.needs_terms_acceptance(cx) {
 8973            return Some(
 8974                h_flex()
 8975                    .min_w(min_width)
 8976                    .flex_1()
 8977                    .px_2()
 8978                    .py_1()
 8979                    .gap_3()
 8980                    .elevation_2(cx)
 8981                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8982                    .id("accept-terms")
 8983                    .cursor_pointer()
 8984                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8985                    .on_click(cx.listener(|this, _event, window, cx| {
 8986                        cx.stop_propagation();
 8987                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8988                        window.dispatch_action(
 8989                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8990                            cx,
 8991                        );
 8992                    }))
 8993                    .child(
 8994                        h_flex()
 8995                            .flex_1()
 8996                            .gap_2()
 8997                            .child(Icon::new(IconName::ZedPredict))
 8998                            .child(Label::new("Accept Terms of Service"))
 8999                            .child(div().w_full())
 9000                            .child(
 9001                                Icon::new(IconName::ArrowUpRight)
 9002                                    .color(Color::Muted)
 9003                                    .size(IconSize::Small),
 9004                            )
 9005                            .into_any_element(),
 9006                    )
 9007                    .into_any(),
 9008            );
 9009        }
 9010
 9011        let is_refreshing = provider.provider.is_refreshing(cx);
 9012
 9013        fn pending_completion_container() -> Div {
 9014            h_flex()
 9015                .h_full()
 9016                .flex_1()
 9017                .gap_2()
 9018                .child(Icon::new(IconName::ZedPredict))
 9019        }
 9020
 9021        let completion = match &self.active_inline_completion {
 9022            Some(prediction) => {
 9023                if !self.has_visible_completions_menu() {
 9024                    const RADIUS: Pixels = px(6.);
 9025                    const BORDER_WIDTH: Pixels = px(1.);
 9026
 9027                    return Some(
 9028                        h_flex()
 9029                            .elevation_2(cx)
 9030                            .border(BORDER_WIDTH)
 9031                            .border_color(cx.theme().colors().border)
 9032                            .when(accept_keystroke.is_none(), |el| {
 9033                                el.border_color(cx.theme().status().error)
 9034                            })
 9035                            .rounded(RADIUS)
 9036                            .rounded_tl(px(0.))
 9037                            .overflow_hidden()
 9038                            .child(div().px_1p5().child(match &prediction.completion {
 9039                                InlineCompletion::Move { target, snapshot } => {
 9040                                    use text::ToPoint as _;
 9041                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9042                                    {
 9043                                        Icon::new(IconName::ZedPredictDown)
 9044                                    } else {
 9045                                        Icon::new(IconName::ZedPredictUp)
 9046                                    }
 9047                                }
 9048                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9049                            }))
 9050                            .child(
 9051                                h_flex()
 9052                                    .gap_1()
 9053                                    .py_1()
 9054                                    .px_2()
 9055                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9056                                    .border_l_1()
 9057                                    .border_color(cx.theme().colors().border)
 9058                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9059                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9060                                        el.child(
 9061                                            Label::new("Hold")
 9062                                                .size(LabelSize::Small)
 9063                                                .when(accept_keystroke.is_none(), |el| {
 9064                                                    el.strikethrough()
 9065                                                })
 9066                                                .line_height_style(LineHeightStyle::UiLabel),
 9067                                        )
 9068                                    })
 9069                                    .id("edit_prediction_cursor_popover_keybind")
 9070                                    .when(accept_keystroke.is_none(), |el| {
 9071                                        let status_colors = cx.theme().status();
 9072
 9073                                        el.bg(status_colors.error_background)
 9074                                            .border_color(status_colors.error.opacity(0.6))
 9075                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9076                                            .cursor_default()
 9077                                            .hoverable_tooltip(move |_window, cx| {
 9078                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9079                                                    .into()
 9080                                            })
 9081                                    })
 9082                                    .when_some(
 9083                                        accept_keystroke.as_ref(),
 9084                                        |el, accept_keystroke| {
 9085                                            el.child(h_flex().children(ui::render_modifiers(
 9086                                                &accept_keystroke.modifiers,
 9087                                                PlatformStyle::platform(),
 9088                                                Some(Color::Default),
 9089                                                Some(IconSize::XSmall.rems().into()),
 9090                                                false,
 9091                                            )))
 9092                                        },
 9093                                    ),
 9094                            )
 9095                            .into_any(),
 9096                    );
 9097                }
 9098
 9099                self.render_edit_prediction_cursor_popover_preview(
 9100                    prediction,
 9101                    cursor_point,
 9102                    style,
 9103                    cx,
 9104                )?
 9105            }
 9106
 9107            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9108                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9109                    stale_completion,
 9110                    cursor_point,
 9111                    style,
 9112                    cx,
 9113                )?,
 9114
 9115                None => {
 9116                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9117                }
 9118            },
 9119
 9120            None => pending_completion_container().child(Label::new("No Prediction")),
 9121        };
 9122
 9123        let completion = if is_refreshing {
 9124            completion
 9125                .with_animation(
 9126                    "loading-completion",
 9127                    Animation::new(Duration::from_secs(2))
 9128                        .repeat()
 9129                        .with_easing(pulsating_between(0.4, 0.8)),
 9130                    |label, delta| label.opacity(delta),
 9131                )
 9132                .into_any_element()
 9133        } else {
 9134            completion.into_any_element()
 9135        };
 9136
 9137        let has_completion = self.active_inline_completion.is_some();
 9138
 9139        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9140        Some(
 9141            h_flex()
 9142                .min_w(min_width)
 9143                .max_w(max_width)
 9144                .flex_1()
 9145                .elevation_2(cx)
 9146                .border_color(cx.theme().colors().border)
 9147                .child(
 9148                    div()
 9149                        .flex_1()
 9150                        .py_1()
 9151                        .px_2()
 9152                        .overflow_hidden()
 9153                        .child(completion),
 9154                )
 9155                .when_some(accept_keystroke, |el, accept_keystroke| {
 9156                    if !accept_keystroke.modifiers.modified() {
 9157                        return el;
 9158                    }
 9159
 9160                    el.child(
 9161                        h_flex()
 9162                            .h_full()
 9163                            .border_l_1()
 9164                            .rounded_r_lg()
 9165                            .border_color(cx.theme().colors().border)
 9166                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9167                            .gap_1()
 9168                            .py_1()
 9169                            .px_2()
 9170                            .child(
 9171                                h_flex()
 9172                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9173                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9174                                    .child(h_flex().children(ui::render_modifiers(
 9175                                        &accept_keystroke.modifiers,
 9176                                        PlatformStyle::platform(),
 9177                                        Some(if !has_completion {
 9178                                            Color::Muted
 9179                                        } else {
 9180                                            Color::Default
 9181                                        }),
 9182                                        None,
 9183                                        false,
 9184                                    ))),
 9185                            )
 9186                            .child(Label::new("Preview").into_any_element())
 9187                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9188                    )
 9189                })
 9190                .into_any(),
 9191        )
 9192    }
 9193
 9194    fn render_edit_prediction_cursor_popover_preview(
 9195        &self,
 9196        completion: &InlineCompletionState,
 9197        cursor_point: Point,
 9198        style: &EditorStyle,
 9199        cx: &mut Context<Editor>,
 9200    ) -> Option<Div> {
 9201        use text::ToPoint as _;
 9202
 9203        fn render_relative_row_jump(
 9204            prefix: impl Into<String>,
 9205            current_row: u32,
 9206            target_row: u32,
 9207        ) -> Div {
 9208            let (row_diff, arrow) = if target_row < current_row {
 9209                (current_row - target_row, IconName::ArrowUp)
 9210            } else {
 9211                (target_row - current_row, IconName::ArrowDown)
 9212            };
 9213
 9214            h_flex()
 9215                .child(
 9216                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9217                        .color(Color::Muted)
 9218                        .size(LabelSize::Small),
 9219                )
 9220                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9221        }
 9222
 9223        match &completion.completion {
 9224            InlineCompletion::Move {
 9225                target, snapshot, ..
 9226            } => Some(
 9227                h_flex()
 9228                    .px_2()
 9229                    .gap_2()
 9230                    .flex_1()
 9231                    .child(
 9232                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9233                            Icon::new(IconName::ZedPredictDown)
 9234                        } else {
 9235                            Icon::new(IconName::ZedPredictUp)
 9236                        },
 9237                    )
 9238                    .child(Label::new("Jump to Edit")),
 9239            ),
 9240
 9241            InlineCompletion::Edit {
 9242                edits,
 9243                edit_preview,
 9244                snapshot,
 9245                display_mode: _,
 9246            } => {
 9247                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9248
 9249                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9250                    &snapshot,
 9251                    &edits,
 9252                    edit_preview.as_ref()?,
 9253                    true,
 9254                    cx,
 9255                )
 9256                .first_line_preview();
 9257
 9258                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9259                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9260
 9261                let preview = h_flex()
 9262                    .gap_1()
 9263                    .min_w_16()
 9264                    .child(styled_text)
 9265                    .when(has_more_lines, |parent| parent.child(""));
 9266
 9267                let left = if first_edit_row != cursor_point.row {
 9268                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9269                        .into_any_element()
 9270                } else {
 9271                    Icon::new(IconName::ZedPredict).into_any_element()
 9272                };
 9273
 9274                Some(
 9275                    h_flex()
 9276                        .h_full()
 9277                        .flex_1()
 9278                        .gap_2()
 9279                        .pr_1()
 9280                        .overflow_x_hidden()
 9281                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9282                        .child(left)
 9283                        .child(preview),
 9284                )
 9285            }
 9286        }
 9287    }
 9288
 9289    pub fn render_context_menu(
 9290        &self,
 9291        style: &EditorStyle,
 9292        max_height_in_lines: u32,
 9293        window: &mut Window,
 9294        cx: &mut Context<Editor>,
 9295    ) -> Option<AnyElement> {
 9296        let menu = self.context_menu.borrow();
 9297        let menu = menu.as_ref()?;
 9298        if !menu.visible() {
 9299            return None;
 9300        };
 9301        Some(menu.render(style, max_height_in_lines, window, cx))
 9302    }
 9303
 9304    fn render_context_menu_aside(
 9305        &mut self,
 9306        max_size: Size<Pixels>,
 9307        window: &mut Window,
 9308        cx: &mut Context<Editor>,
 9309    ) -> Option<AnyElement> {
 9310        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9311            if menu.visible() {
 9312                menu.render_aside(max_size, window, cx)
 9313            } else {
 9314                None
 9315            }
 9316        })
 9317    }
 9318
 9319    fn hide_context_menu(
 9320        &mut self,
 9321        window: &mut Window,
 9322        cx: &mut Context<Self>,
 9323    ) -> Option<CodeContextMenu> {
 9324        cx.notify();
 9325        self.completion_tasks.clear();
 9326        let context_menu = self.context_menu.borrow_mut().take();
 9327        self.stale_inline_completion_in_menu.take();
 9328        self.update_visible_inline_completion(window, cx);
 9329        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9330            if let Some(completion_provider) = &self.completion_provider {
 9331                completion_provider.selection_changed(None, window, cx);
 9332            }
 9333        }
 9334        context_menu
 9335    }
 9336
 9337    fn show_snippet_choices(
 9338        &mut self,
 9339        choices: &Vec<String>,
 9340        selection: Range<Anchor>,
 9341        cx: &mut Context<Self>,
 9342    ) {
 9343        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9344            (Some(a), Some(b)) if a == b => a,
 9345            _ => {
 9346                log::error!("expected anchor range to have matching buffer IDs");
 9347                return;
 9348            }
 9349        };
 9350        let multi_buffer = self.buffer().read(cx);
 9351        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9352            return;
 9353        };
 9354
 9355        let id = post_inc(&mut self.next_completion_id);
 9356        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9357        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9358            CompletionsMenu::new_snippet_choices(
 9359                id,
 9360                true,
 9361                choices,
 9362                selection,
 9363                buffer,
 9364                snippet_sort_order,
 9365            ),
 9366        ));
 9367    }
 9368
 9369    pub fn insert_snippet(
 9370        &mut self,
 9371        insertion_ranges: &[Range<usize>],
 9372        snippet: Snippet,
 9373        window: &mut Window,
 9374        cx: &mut Context<Self>,
 9375    ) -> Result<()> {
 9376        struct Tabstop<T> {
 9377            is_end_tabstop: bool,
 9378            ranges: Vec<Range<T>>,
 9379            choices: Option<Vec<String>>,
 9380        }
 9381
 9382        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9383            let snippet_text: Arc<str> = snippet.text.clone().into();
 9384            let edits = insertion_ranges
 9385                .iter()
 9386                .cloned()
 9387                .map(|range| (range, snippet_text.clone()));
 9388            let autoindent_mode = AutoindentMode::Block {
 9389                original_indent_columns: Vec::new(),
 9390            };
 9391            buffer.edit(edits, Some(autoindent_mode), cx);
 9392
 9393            let snapshot = &*buffer.read(cx);
 9394            let snippet = &snippet;
 9395            snippet
 9396                .tabstops
 9397                .iter()
 9398                .map(|tabstop| {
 9399                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9400                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9401                    });
 9402                    let mut tabstop_ranges = tabstop
 9403                        .ranges
 9404                        .iter()
 9405                        .flat_map(|tabstop_range| {
 9406                            let mut delta = 0_isize;
 9407                            insertion_ranges.iter().map(move |insertion_range| {
 9408                                let insertion_start = insertion_range.start as isize + delta;
 9409                                delta +=
 9410                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9411
 9412                                let start = ((insertion_start + tabstop_range.start) as usize)
 9413                                    .min(snapshot.len());
 9414                                let end = ((insertion_start + tabstop_range.end) as usize)
 9415                                    .min(snapshot.len());
 9416                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9417                            })
 9418                        })
 9419                        .collect::<Vec<_>>();
 9420                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9421
 9422                    Tabstop {
 9423                        is_end_tabstop,
 9424                        ranges: tabstop_ranges,
 9425                        choices: tabstop.choices.clone(),
 9426                    }
 9427                })
 9428                .collect::<Vec<_>>()
 9429        });
 9430        if let Some(tabstop) = tabstops.first() {
 9431            self.change_selections(Default::default(), window, cx, |s| {
 9432                // Reverse order so that the first range is the newest created selection.
 9433                // Completions will use it and autoscroll will prioritize it.
 9434                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9435            });
 9436
 9437            if let Some(choices) = &tabstop.choices {
 9438                if let Some(selection) = tabstop.ranges.first() {
 9439                    self.show_snippet_choices(choices, selection.clone(), cx)
 9440                }
 9441            }
 9442
 9443            // If we're already at the last tabstop and it's at the end of the snippet,
 9444            // we're done, we don't need to keep the state around.
 9445            if !tabstop.is_end_tabstop {
 9446                let choices = tabstops
 9447                    .iter()
 9448                    .map(|tabstop| tabstop.choices.clone())
 9449                    .collect();
 9450
 9451                let ranges = tabstops
 9452                    .into_iter()
 9453                    .map(|tabstop| tabstop.ranges)
 9454                    .collect::<Vec<_>>();
 9455
 9456                self.snippet_stack.push(SnippetState {
 9457                    active_index: 0,
 9458                    ranges,
 9459                    choices,
 9460                });
 9461            }
 9462
 9463            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9464            if self.autoclose_regions.is_empty() {
 9465                let snapshot = self.buffer.read(cx).snapshot(cx);
 9466                for selection in &mut self.selections.all::<Point>(cx) {
 9467                    let selection_head = selection.head();
 9468                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9469                        continue;
 9470                    };
 9471
 9472                    let mut bracket_pair = None;
 9473                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9474                    let prev_chars = snapshot
 9475                        .reversed_chars_at(selection_head)
 9476                        .collect::<String>();
 9477                    for (pair, enabled) in scope.brackets() {
 9478                        if enabled
 9479                            && pair.close
 9480                            && prev_chars.starts_with(pair.start.as_str())
 9481                            && next_chars.starts_with(pair.end.as_str())
 9482                        {
 9483                            bracket_pair = Some(pair.clone());
 9484                            break;
 9485                        }
 9486                    }
 9487                    if let Some(pair) = bracket_pair {
 9488                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9489                        let autoclose_enabled =
 9490                            self.use_autoclose && snapshot_settings.use_autoclose;
 9491                        if autoclose_enabled {
 9492                            let start = snapshot.anchor_after(selection_head);
 9493                            let end = snapshot.anchor_after(selection_head);
 9494                            self.autoclose_regions.push(AutocloseRegion {
 9495                                selection_id: selection.id,
 9496                                range: start..end,
 9497                                pair,
 9498                            });
 9499                        }
 9500                    }
 9501                }
 9502            }
 9503        }
 9504        Ok(())
 9505    }
 9506
 9507    pub fn move_to_next_snippet_tabstop(
 9508        &mut self,
 9509        window: &mut Window,
 9510        cx: &mut Context<Self>,
 9511    ) -> bool {
 9512        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9513    }
 9514
 9515    pub fn move_to_prev_snippet_tabstop(
 9516        &mut self,
 9517        window: &mut Window,
 9518        cx: &mut Context<Self>,
 9519    ) -> bool {
 9520        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9521    }
 9522
 9523    pub fn move_to_snippet_tabstop(
 9524        &mut self,
 9525        bias: Bias,
 9526        window: &mut Window,
 9527        cx: &mut Context<Self>,
 9528    ) -> bool {
 9529        if let Some(mut snippet) = self.snippet_stack.pop() {
 9530            match bias {
 9531                Bias::Left => {
 9532                    if snippet.active_index > 0 {
 9533                        snippet.active_index -= 1;
 9534                    } else {
 9535                        self.snippet_stack.push(snippet);
 9536                        return false;
 9537                    }
 9538                }
 9539                Bias::Right => {
 9540                    if snippet.active_index + 1 < snippet.ranges.len() {
 9541                        snippet.active_index += 1;
 9542                    } else {
 9543                        self.snippet_stack.push(snippet);
 9544                        return false;
 9545                    }
 9546                }
 9547            }
 9548            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9549                self.change_selections(Default::default(), window, cx, |s| {
 9550                    // Reverse order so that the first range is the newest created selection.
 9551                    // Completions will use it and autoscroll will prioritize it.
 9552                    s.select_ranges(current_ranges.iter().rev().cloned())
 9553                });
 9554
 9555                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9556                    if let Some(selection) = current_ranges.first() {
 9557                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9558                    }
 9559                }
 9560
 9561                // If snippet state is not at the last tabstop, push it back on the stack
 9562                if snippet.active_index + 1 < snippet.ranges.len() {
 9563                    self.snippet_stack.push(snippet);
 9564                }
 9565                return true;
 9566            }
 9567        }
 9568
 9569        false
 9570    }
 9571
 9572    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9573        self.transact(window, cx, |this, window, cx| {
 9574            this.select_all(&SelectAll, window, cx);
 9575            this.insert("", window, cx);
 9576        });
 9577    }
 9578
 9579    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9580        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9581        self.transact(window, cx, |this, window, cx| {
 9582            this.select_autoclose_pair(window, cx);
 9583            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9584            if !this.linked_edit_ranges.is_empty() {
 9585                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9586                let snapshot = this.buffer.read(cx).snapshot(cx);
 9587
 9588                for selection in selections.iter() {
 9589                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9590                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9591                    if selection_start.buffer_id != selection_end.buffer_id {
 9592                        continue;
 9593                    }
 9594                    if let Some(ranges) =
 9595                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9596                    {
 9597                        for (buffer, entries) in ranges {
 9598                            linked_ranges.entry(buffer).or_default().extend(entries);
 9599                        }
 9600                    }
 9601                }
 9602            }
 9603
 9604            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9605            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9606            for selection in &mut selections {
 9607                if selection.is_empty() {
 9608                    let old_head = selection.head();
 9609                    let mut new_head =
 9610                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9611                            .to_point(&display_map);
 9612                    if let Some((buffer, line_buffer_range)) = display_map
 9613                        .buffer_snapshot
 9614                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9615                    {
 9616                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9617                        let indent_len = match indent_size.kind {
 9618                            IndentKind::Space => {
 9619                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9620                            }
 9621                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9622                        };
 9623                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9624                            let indent_len = indent_len.get();
 9625                            new_head = cmp::min(
 9626                                new_head,
 9627                                MultiBufferPoint::new(
 9628                                    old_head.row,
 9629                                    ((old_head.column - 1) / indent_len) * indent_len,
 9630                                ),
 9631                            );
 9632                        }
 9633                    }
 9634
 9635                    selection.set_head(new_head, SelectionGoal::None);
 9636                }
 9637            }
 9638
 9639            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9640            this.insert("", window, cx);
 9641            let empty_str: Arc<str> = Arc::from("");
 9642            for (buffer, edits) in linked_ranges {
 9643                let snapshot = buffer.read(cx).snapshot();
 9644                use text::ToPoint as TP;
 9645
 9646                let edits = edits
 9647                    .into_iter()
 9648                    .map(|range| {
 9649                        let end_point = TP::to_point(&range.end, &snapshot);
 9650                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9651
 9652                        if end_point == start_point {
 9653                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9654                                .saturating_sub(1);
 9655                            start_point =
 9656                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9657                        };
 9658
 9659                        (start_point..end_point, empty_str.clone())
 9660                    })
 9661                    .sorted_by_key(|(range, _)| range.start)
 9662                    .collect::<Vec<_>>();
 9663                buffer.update(cx, |this, cx| {
 9664                    this.edit(edits, None, cx);
 9665                })
 9666            }
 9667            this.refresh_inline_completion(true, false, window, cx);
 9668            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9669        });
 9670    }
 9671
 9672    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9673        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9674        self.transact(window, cx, |this, window, cx| {
 9675            this.change_selections(Default::default(), window, cx, |s| {
 9676                s.move_with(|map, selection| {
 9677                    if selection.is_empty() {
 9678                        let cursor = movement::right(map, selection.head());
 9679                        selection.end = cursor;
 9680                        selection.reversed = true;
 9681                        selection.goal = SelectionGoal::None;
 9682                    }
 9683                })
 9684            });
 9685            this.insert("", window, cx);
 9686            this.refresh_inline_completion(true, false, window, cx);
 9687        });
 9688    }
 9689
 9690    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9691        if self.mode.is_single_line() {
 9692            cx.propagate();
 9693            return;
 9694        }
 9695
 9696        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9697        if self.move_to_prev_snippet_tabstop(window, cx) {
 9698            return;
 9699        }
 9700        self.outdent(&Outdent, window, cx);
 9701    }
 9702
 9703    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9704        if self.mode.is_single_line() {
 9705            cx.propagate();
 9706            return;
 9707        }
 9708
 9709        if self.move_to_next_snippet_tabstop(window, cx) {
 9710            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9711            return;
 9712        }
 9713        if self.read_only(cx) {
 9714            return;
 9715        }
 9716        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9717        let mut selections = self.selections.all_adjusted(cx);
 9718        let buffer = self.buffer.read(cx);
 9719        let snapshot = buffer.snapshot(cx);
 9720        let rows_iter = selections.iter().map(|s| s.head().row);
 9721        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9722
 9723        let has_some_cursor_in_whitespace = selections
 9724            .iter()
 9725            .filter(|selection| selection.is_empty())
 9726            .any(|selection| {
 9727                let cursor = selection.head();
 9728                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9729                cursor.column < current_indent.len
 9730            });
 9731
 9732        let mut edits = Vec::new();
 9733        let mut prev_edited_row = 0;
 9734        let mut row_delta = 0;
 9735        for selection in &mut selections {
 9736            if selection.start.row != prev_edited_row {
 9737                row_delta = 0;
 9738            }
 9739            prev_edited_row = selection.end.row;
 9740
 9741            // If the selection is non-empty, then increase the indentation of the selected lines.
 9742            if !selection.is_empty() {
 9743                row_delta =
 9744                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9745                continue;
 9746            }
 9747
 9748            let cursor = selection.head();
 9749            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9750            if let Some(suggested_indent) =
 9751                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9752            {
 9753                // Don't do anything if already at suggested indent
 9754                // and there is any other cursor which is not
 9755                if has_some_cursor_in_whitespace
 9756                    && cursor.column == current_indent.len
 9757                    && current_indent.len == suggested_indent.len
 9758                {
 9759                    continue;
 9760                }
 9761
 9762                // Adjust line and move cursor to suggested indent
 9763                // if cursor is not at suggested indent
 9764                if cursor.column < suggested_indent.len
 9765                    && cursor.column <= current_indent.len
 9766                    && current_indent.len <= suggested_indent.len
 9767                {
 9768                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9769                    selection.end = selection.start;
 9770                    if row_delta == 0 {
 9771                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9772                            cursor.row,
 9773                            current_indent,
 9774                            suggested_indent,
 9775                        ));
 9776                        row_delta = suggested_indent.len - current_indent.len;
 9777                    }
 9778                    continue;
 9779                }
 9780
 9781                // If current indent is more than suggested indent
 9782                // only move cursor to current indent and skip indent
 9783                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9784                    selection.start = Point::new(cursor.row, current_indent.len);
 9785                    selection.end = selection.start;
 9786                    continue;
 9787                }
 9788            }
 9789
 9790            // Otherwise, insert a hard or soft tab.
 9791            let settings = buffer.language_settings_at(cursor, cx);
 9792            let tab_size = if settings.hard_tabs {
 9793                IndentSize::tab()
 9794            } else {
 9795                let tab_size = settings.tab_size.get();
 9796                let indent_remainder = snapshot
 9797                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9798                    .flat_map(str::chars)
 9799                    .fold(row_delta % tab_size, |counter: u32, c| {
 9800                        if c == '\t' {
 9801                            0
 9802                        } else {
 9803                            (counter + 1) % tab_size
 9804                        }
 9805                    });
 9806
 9807                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9808                IndentSize::spaces(chars_to_next_tab_stop)
 9809            };
 9810            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9811            selection.end = selection.start;
 9812            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9813            row_delta += tab_size.len;
 9814        }
 9815
 9816        self.transact(window, cx, |this, window, cx| {
 9817            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9818            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9819            this.refresh_inline_completion(true, false, window, cx);
 9820        });
 9821    }
 9822
 9823    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9824        if self.read_only(cx) {
 9825            return;
 9826        }
 9827        if self.mode.is_single_line() {
 9828            cx.propagate();
 9829            return;
 9830        }
 9831
 9832        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9833        let mut selections = self.selections.all::<Point>(cx);
 9834        let mut prev_edited_row = 0;
 9835        let mut row_delta = 0;
 9836        let mut edits = Vec::new();
 9837        let buffer = self.buffer.read(cx);
 9838        let snapshot = buffer.snapshot(cx);
 9839        for selection in &mut selections {
 9840            if selection.start.row != prev_edited_row {
 9841                row_delta = 0;
 9842            }
 9843            prev_edited_row = selection.end.row;
 9844
 9845            row_delta =
 9846                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9847        }
 9848
 9849        self.transact(window, cx, |this, window, cx| {
 9850            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9851            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9852        });
 9853    }
 9854
 9855    fn indent_selection(
 9856        buffer: &MultiBuffer,
 9857        snapshot: &MultiBufferSnapshot,
 9858        selection: &mut Selection<Point>,
 9859        edits: &mut Vec<(Range<Point>, String)>,
 9860        delta_for_start_row: u32,
 9861        cx: &App,
 9862    ) -> u32 {
 9863        let settings = buffer.language_settings_at(selection.start, cx);
 9864        let tab_size = settings.tab_size.get();
 9865        let indent_kind = if settings.hard_tabs {
 9866            IndentKind::Tab
 9867        } else {
 9868            IndentKind::Space
 9869        };
 9870        let mut start_row = selection.start.row;
 9871        let mut end_row = selection.end.row + 1;
 9872
 9873        // If a selection ends at the beginning of a line, don't indent
 9874        // that last line.
 9875        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9876            end_row -= 1;
 9877        }
 9878
 9879        // Avoid re-indenting a row that has already been indented by a
 9880        // previous selection, but still update this selection's column
 9881        // to reflect that indentation.
 9882        if delta_for_start_row > 0 {
 9883            start_row += 1;
 9884            selection.start.column += delta_for_start_row;
 9885            if selection.end.row == selection.start.row {
 9886                selection.end.column += delta_for_start_row;
 9887            }
 9888        }
 9889
 9890        let mut delta_for_end_row = 0;
 9891        let has_multiple_rows = start_row + 1 != end_row;
 9892        for row in start_row..end_row {
 9893            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9894            let indent_delta = match (current_indent.kind, indent_kind) {
 9895                (IndentKind::Space, IndentKind::Space) => {
 9896                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9897                    IndentSize::spaces(columns_to_next_tab_stop)
 9898                }
 9899                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9900                (_, IndentKind::Tab) => IndentSize::tab(),
 9901            };
 9902
 9903            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9904                0
 9905            } else {
 9906                selection.start.column
 9907            };
 9908            let row_start = Point::new(row, start);
 9909            edits.push((
 9910                row_start..row_start,
 9911                indent_delta.chars().collect::<String>(),
 9912            ));
 9913
 9914            // Update this selection's endpoints to reflect the indentation.
 9915            if row == selection.start.row {
 9916                selection.start.column += indent_delta.len;
 9917            }
 9918            if row == selection.end.row {
 9919                selection.end.column += indent_delta.len;
 9920                delta_for_end_row = indent_delta.len;
 9921            }
 9922        }
 9923
 9924        if selection.start.row == selection.end.row {
 9925            delta_for_start_row + delta_for_end_row
 9926        } else {
 9927            delta_for_end_row
 9928        }
 9929    }
 9930
 9931    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9932        if self.read_only(cx) {
 9933            return;
 9934        }
 9935        if self.mode.is_single_line() {
 9936            cx.propagate();
 9937            return;
 9938        }
 9939
 9940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9941        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9942        let selections = self.selections.all::<Point>(cx);
 9943        let mut deletion_ranges = Vec::new();
 9944        let mut last_outdent = None;
 9945        {
 9946            let buffer = self.buffer.read(cx);
 9947            let snapshot = buffer.snapshot(cx);
 9948            for selection in &selections {
 9949                let settings = buffer.language_settings_at(selection.start, cx);
 9950                let tab_size = settings.tab_size.get();
 9951                let mut rows = selection.spanned_rows(false, &display_map);
 9952
 9953                // Avoid re-outdenting a row that has already been outdented by a
 9954                // previous selection.
 9955                if let Some(last_row) = last_outdent {
 9956                    if last_row == rows.start {
 9957                        rows.start = rows.start.next_row();
 9958                    }
 9959                }
 9960                let has_multiple_rows = rows.len() > 1;
 9961                for row in rows.iter_rows() {
 9962                    let indent_size = snapshot.indent_size_for_line(row);
 9963                    if indent_size.len > 0 {
 9964                        let deletion_len = match indent_size.kind {
 9965                            IndentKind::Space => {
 9966                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9967                                if columns_to_prev_tab_stop == 0 {
 9968                                    tab_size
 9969                                } else {
 9970                                    columns_to_prev_tab_stop
 9971                                }
 9972                            }
 9973                            IndentKind::Tab => 1,
 9974                        };
 9975                        let start = if has_multiple_rows
 9976                            || deletion_len > selection.start.column
 9977                            || indent_size.len < selection.start.column
 9978                        {
 9979                            0
 9980                        } else {
 9981                            selection.start.column - deletion_len
 9982                        };
 9983                        deletion_ranges.push(
 9984                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9985                        );
 9986                        last_outdent = Some(row);
 9987                    }
 9988                }
 9989            }
 9990        }
 9991
 9992        self.transact(window, cx, |this, window, cx| {
 9993            this.buffer.update(cx, |buffer, cx| {
 9994                let empty_str: Arc<str> = Arc::default();
 9995                buffer.edit(
 9996                    deletion_ranges
 9997                        .into_iter()
 9998                        .map(|range| (range, empty_str.clone())),
 9999                    None,
10000                    cx,
10001                );
10002            });
10003            let selections = this.selections.all::<usize>(cx);
10004            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10005        });
10006    }
10007
10008    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10009        if self.read_only(cx) {
10010            return;
10011        }
10012        if self.mode.is_single_line() {
10013            cx.propagate();
10014            return;
10015        }
10016
10017        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10018        let selections = self
10019            .selections
10020            .all::<usize>(cx)
10021            .into_iter()
10022            .map(|s| s.range());
10023
10024        self.transact(window, cx, |this, window, cx| {
10025            this.buffer.update(cx, |buffer, cx| {
10026                buffer.autoindent_ranges(selections, cx);
10027            });
10028            let selections = this.selections.all::<usize>(cx);
10029            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10030        });
10031    }
10032
10033    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10034        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10035        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10036        let selections = self.selections.all::<Point>(cx);
10037
10038        let mut new_cursors = Vec::new();
10039        let mut edit_ranges = Vec::new();
10040        let mut selections = selections.iter().peekable();
10041        while let Some(selection) = selections.next() {
10042            let mut rows = selection.spanned_rows(false, &display_map);
10043            let goal_display_column = selection.head().to_display_point(&display_map).column();
10044
10045            // Accumulate contiguous regions of rows that we want to delete.
10046            while let Some(next_selection) = selections.peek() {
10047                let next_rows = next_selection.spanned_rows(false, &display_map);
10048                if next_rows.start <= rows.end {
10049                    rows.end = next_rows.end;
10050                    selections.next().unwrap();
10051                } else {
10052                    break;
10053                }
10054            }
10055
10056            let buffer = &display_map.buffer_snapshot;
10057            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10058            let edit_end;
10059            let cursor_buffer_row;
10060            if buffer.max_point().row >= rows.end.0 {
10061                // If there's a line after the range, delete the \n from the end of the row range
10062                // and position the cursor on the next line.
10063                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10064                cursor_buffer_row = rows.end;
10065            } else {
10066                // If there isn't a line after the range, delete the \n from the line before the
10067                // start of the row range and position the cursor there.
10068                edit_start = edit_start.saturating_sub(1);
10069                edit_end = buffer.len();
10070                cursor_buffer_row = rows.start.previous_row();
10071            }
10072
10073            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10074            *cursor.column_mut() =
10075                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10076
10077            new_cursors.push((
10078                selection.id,
10079                buffer.anchor_after(cursor.to_point(&display_map)),
10080            ));
10081            edit_ranges.push(edit_start..edit_end);
10082        }
10083
10084        self.transact(window, cx, |this, window, cx| {
10085            let buffer = this.buffer.update(cx, |buffer, cx| {
10086                let empty_str: Arc<str> = Arc::default();
10087                buffer.edit(
10088                    edit_ranges
10089                        .into_iter()
10090                        .map(|range| (range, empty_str.clone())),
10091                    None,
10092                    cx,
10093                );
10094                buffer.snapshot(cx)
10095            });
10096            let new_selections = new_cursors
10097                .into_iter()
10098                .map(|(id, cursor)| {
10099                    let cursor = cursor.to_point(&buffer);
10100                    Selection {
10101                        id,
10102                        start: cursor,
10103                        end: cursor,
10104                        reversed: false,
10105                        goal: SelectionGoal::None,
10106                    }
10107                })
10108                .collect();
10109
10110            this.change_selections(Default::default(), window, cx, |s| {
10111                s.select(new_selections);
10112            });
10113        });
10114    }
10115
10116    pub fn join_lines_impl(
10117        &mut self,
10118        insert_whitespace: bool,
10119        window: &mut Window,
10120        cx: &mut Context<Self>,
10121    ) {
10122        if self.read_only(cx) {
10123            return;
10124        }
10125        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10126        for selection in self.selections.all::<Point>(cx) {
10127            let start = MultiBufferRow(selection.start.row);
10128            // Treat single line selections as if they include the next line. Otherwise this action
10129            // would do nothing for single line selections individual cursors.
10130            let end = if selection.start.row == selection.end.row {
10131                MultiBufferRow(selection.start.row + 1)
10132            } else {
10133                MultiBufferRow(selection.end.row)
10134            };
10135
10136            if let Some(last_row_range) = row_ranges.last_mut() {
10137                if start <= last_row_range.end {
10138                    last_row_range.end = end;
10139                    continue;
10140                }
10141            }
10142            row_ranges.push(start..end);
10143        }
10144
10145        let snapshot = self.buffer.read(cx).snapshot(cx);
10146        let mut cursor_positions = Vec::new();
10147        for row_range in &row_ranges {
10148            let anchor = snapshot.anchor_before(Point::new(
10149                row_range.end.previous_row().0,
10150                snapshot.line_len(row_range.end.previous_row()),
10151            ));
10152            cursor_positions.push(anchor..anchor);
10153        }
10154
10155        self.transact(window, cx, |this, window, cx| {
10156            for row_range in row_ranges.into_iter().rev() {
10157                for row in row_range.iter_rows().rev() {
10158                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10159                    let next_line_row = row.next_row();
10160                    let indent = snapshot.indent_size_for_line(next_line_row);
10161                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10162
10163                    let replace =
10164                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10165                            " "
10166                        } else {
10167                            ""
10168                        };
10169
10170                    this.buffer.update(cx, |buffer, cx| {
10171                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10172                    });
10173                }
10174            }
10175
10176            this.change_selections(Default::default(), window, cx, |s| {
10177                s.select_anchor_ranges(cursor_positions)
10178            });
10179        });
10180    }
10181
10182    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10183        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10184        self.join_lines_impl(true, window, cx);
10185    }
10186
10187    pub fn sort_lines_case_sensitive(
10188        &mut self,
10189        _: &SortLinesCaseSensitive,
10190        window: &mut Window,
10191        cx: &mut Context<Self>,
10192    ) {
10193        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10194    }
10195
10196    pub fn sort_lines_case_insensitive(
10197        &mut self,
10198        _: &SortLinesCaseInsensitive,
10199        window: &mut Window,
10200        cx: &mut Context<Self>,
10201    ) {
10202        self.manipulate_immutable_lines(window, cx, |lines| {
10203            lines.sort_by_key(|line| line.to_lowercase())
10204        })
10205    }
10206
10207    pub fn unique_lines_case_insensitive(
10208        &mut self,
10209        _: &UniqueLinesCaseInsensitive,
10210        window: &mut Window,
10211        cx: &mut Context<Self>,
10212    ) {
10213        self.manipulate_immutable_lines(window, cx, |lines| {
10214            let mut seen = HashSet::default();
10215            lines.retain(|line| seen.insert(line.to_lowercase()));
10216        })
10217    }
10218
10219    pub fn unique_lines_case_sensitive(
10220        &mut self,
10221        _: &UniqueLinesCaseSensitive,
10222        window: &mut Window,
10223        cx: &mut Context<Self>,
10224    ) {
10225        self.manipulate_immutable_lines(window, cx, |lines| {
10226            let mut seen = HashSet::default();
10227            lines.retain(|line| seen.insert(*line));
10228        })
10229    }
10230
10231    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10232        let Some(project) = self.project.clone() else {
10233            return;
10234        };
10235        self.reload(project, window, cx)
10236            .detach_and_notify_err(window, cx);
10237    }
10238
10239    pub fn restore_file(
10240        &mut self,
10241        _: &::git::RestoreFile,
10242        window: &mut Window,
10243        cx: &mut Context<Self>,
10244    ) {
10245        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10246        let mut buffer_ids = HashSet::default();
10247        let snapshot = self.buffer().read(cx).snapshot(cx);
10248        for selection in self.selections.all::<usize>(cx) {
10249            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10250        }
10251
10252        let buffer = self.buffer().read(cx);
10253        let ranges = buffer_ids
10254            .into_iter()
10255            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10256            .collect::<Vec<_>>();
10257
10258        self.restore_hunks_in_ranges(ranges, window, cx);
10259    }
10260
10261    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10262        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10263        let selections = self
10264            .selections
10265            .all(cx)
10266            .into_iter()
10267            .map(|s| s.range())
10268            .collect();
10269        self.restore_hunks_in_ranges(selections, window, cx);
10270    }
10271
10272    pub fn restore_hunks_in_ranges(
10273        &mut self,
10274        ranges: Vec<Range<Point>>,
10275        window: &mut Window,
10276        cx: &mut Context<Editor>,
10277    ) {
10278        let mut revert_changes = HashMap::default();
10279        let chunk_by = self
10280            .snapshot(window, cx)
10281            .hunks_for_ranges(ranges)
10282            .into_iter()
10283            .chunk_by(|hunk| hunk.buffer_id);
10284        for (buffer_id, hunks) in &chunk_by {
10285            let hunks = hunks.collect::<Vec<_>>();
10286            for hunk in &hunks {
10287                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10288            }
10289            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10290        }
10291        drop(chunk_by);
10292        if !revert_changes.is_empty() {
10293            self.transact(window, cx, |editor, window, cx| {
10294                editor.restore(revert_changes, window, cx);
10295            });
10296        }
10297    }
10298
10299    pub fn open_active_item_in_terminal(
10300        &mut self,
10301        _: &OpenInTerminal,
10302        window: &mut Window,
10303        cx: &mut Context<Self>,
10304    ) {
10305        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10306            let project_path = buffer.read(cx).project_path(cx)?;
10307            let project = self.project.as_ref()?.read(cx);
10308            let entry = project.entry_for_path(&project_path, cx)?;
10309            let parent = match &entry.canonical_path {
10310                Some(canonical_path) => canonical_path.to_path_buf(),
10311                None => project.absolute_path(&project_path, cx)?,
10312            }
10313            .parent()?
10314            .to_path_buf();
10315            Some(parent)
10316        }) {
10317            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10318        }
10319    }
10320
10321    fn set_breakpoint_context_menu(
10322        &mut self,
10323        display_row: DisplayRow,
10324        position: Option<Anchor>,
10325        clicked_point: gpui::Point<Pixels>,
10326        window: &mut Window,
10327        cx: &mut Context<Self>,
10328    ) {
10329        let source = self
10330            .buffer
10331            .read(cx)
10332            .snapshot(cx)
10333            .anchor_before(Point::new(display_row.0, 0u32));
10334
10335        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10336
10337        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10338            self,
10339            source,
10340            clicked_point,
10341            context_menu,
10342            window,
10343            cx,
10344        );
10345    }
10346
10347    fn add_edit_breakpoint_block(
10348        &mut self,
10349        anchor: Anchor,
10350        breakpoint: &Breakpoint,
10351        edit_action: BreakpointPromptEditAction,
10352        window: &mut Window,
10353        cx: &mut Context<Self>,
10354    ) {
10355        let weak_editor = cx.weak_entity();
10356        let bp_prompt = cx.new(|cx| {
10357            BreakpointPromptEditor::new(
10358                weak_editor,
10359                anchor,
10360                breakpoint.clone(),
10361                edit_action,
10362                window,
10363                cx,
10364            )
10365        });
10366
10367        let height = bp_prompt.update(cx, |this, cx| {
10368            this.prompt
10369                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10370        });
10371        let cloned_prompt = bp_prompt.clone();
10372        let blocks = vec![BlockProperties {
10373            style: BlockStyle::Sticky,
10374            placement: BlockPlacement::Above(anchor),
10375            height: Some(height),
10376            render: Arc::new(move |cx| {
10377                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10378                cloned_prompt.clone().into_any_element()
10379            }),
10380            priority: 0,
10381            render_in_minimap: true,
10382        }];
10383
10384        let focus_handle = bp_prompt.focus_handle(cx);
10385        window.focus(&focus_handle);
10386
10387        let block_ids = self.insert_blocks(blocks, None, cx);
10388        bp_prompt.update(cx, |prompt, _| {
10389            prompt.add_block_ids(block_ids);
10390        });
10391    }
10392
10393    pub(crate) fn breakpoint_at_row(
10394        &self,
10395        row: u32,
10396        window: &mut Window,
10397        cx: &mut Context<Self>,
10398    ) -> Option<(Anchor, Breakpoint)> {
10399        let snapshot = self.snapshot(window, cx);
10400        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10401
10402        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10403    }
10404
10405    pub(crate) fn breakpoint_at_anchor(
10406        &self,
10407        breakpoint_position: Anchor,
10408        snapshot: &EditorSnapshot,
10409        cx: &mut Context<Self>,
10410    ) -> Option<(Anchor, Breakpoint)> {
10411        let project = self.project.clone()?;
10412
10413        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10414            snapshot
10415                .buffer_snapshot
10416                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10417        })?;
10418
10419        let enclosing_excerpt = breakpoint_position.excerpt_id;
10420        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10421        let buffer_snapshot = buffer.read(cx).snapshot();
10422
10423        let row = buffer_snapshot
10424            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10425            .row;
10426
10427        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10428        let anchor_end = snapshot
10429            .buffer_snapshot
10430            .anchor_after(Point::new(row, line_len));
10431
10432        let bp = self
10433            .breakpoint_store
10434            .as_ref()?
10435            .read_with(cx, |breakpoint_store, cx| {
10436                breakpoint_store
10437                    .breakpoints(
10438                        &buffer,
10439                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10440                        &buffer_snapshot,
10441                        cx,
10442                    )
10443                    .next()
10444                    .and_then(|(bp, _)| {
10445                        let breakpoint_row = buffer_snapshot
10446                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10447                            .row;
10448
10449                        if breakpoint_row == row {
10450                            snapshot
10451                                .buffer_snapshot
10452                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10453                                .map(|position| (position, bp.bp.clone()))
10454                        } else {
10455                            None
10456                        }
10457                    })
10458            });
10459        bp
10460    }
10461
10462    pub fn edit_log_breakpoint(
10463        &mut self,
10464        _: &EditLogBreakpoint,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467    ) {
10468        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10469            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10470                message: None,
10471                state: BreakpointState::Enabled,
10472                condition: None,
10473                hit_condition: None,
10474            });
10475
10476            self.add_edit_breakpoint_block(
10477                anchor,
10478                &breakpoint,
10479                BreakpointPromptEditAction::Log,
10480                window,
10481                cx,
10482            );
10483        }
10484    }
10485
10486    fn breakpoints_at_cursors(
10487        &self,
10488        window: &mut Window,
10489        cx: &mut Context<Self>,
10490    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10491        let snapshot = self.snapshot(window, cx);
10492        let cursors = self
10493            .selections
10494            .disjoint_anchors()
10495            .into_iter()
10496            .map(|selection| {
10497                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10498
10499                let breakpoint_position = self
10500                    .breakpoint_at_row(cursor_position.row, window, cx)
10501                    .map(|bp| bp.0)
10502                    .unwrap_or_else(|| {
10503                        snapshot
10504                            .display_snapshot
10505                            .buffer_snapshot
10506                            .anchor_after(Point::new(cursor_position.row, 0))
10507                    });
10508
10509                let breakpoint = self
10510                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10511                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10512
10513                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10514            })
10515            // 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.
10516            .collect::<HashMap<Anchor, _>>();
10517
10518        cursors.into_iter().collect()
10519    }
10520
10521    pub fn enable_breakpoint(
10522        &mut self,
10523        _: &crate::actions::EnableBreakpoint,
10524        window: &mut Window,
10525        cx: &mut Context<Self>,
10526    ) {
10527        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10528            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10529                continue;
10530            };
10531            self.edit_breakpoint_at_anchor(
10532                anchor,
10533                breakpoint,
10534                BreakpointEditAction::InvertState,
10535                cx,
10536            );
10537        }
10538    }
10539
10540    pub fn disable_breakpoint(
10541        &mut self,
10542        _: &crate::actions::DisableBreakpoint,
10543        window: &mut Window,
10544        cx: &mut Context<Self>,
10545    ) {
10546        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10547            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10548                continue;
10549            };
10550            self.edit_breakpoint_at_anchor(
10551                anchor,
10552                breakpoint,
10553                BreakpointEditAction::InvertState,
10554                cx,
10555            );
10556        }
10557    }
10558
10559    pub fn toggle_breakpoint(
10560        &mut self,
10561        _: &crate::actions::ToggleBreakpoint,
10562        window: &mut Window,
10563        cx: &mut Context<Self>,
10564    ) {
10565        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10566            if let Some(breakpoint) = breakpoint {
10567                self.edit_breakpoint_at_anchor(
10568                    anchor,
10569                    breakpoint,
10570                    BreakpointEditAction::Toggle,
10571                    cx,
10572                );
10573            } else {
10574                self.edit_breakpoint_at_anchor(
10575                    anchor,
10576                    Breakpoint::new_standard(),
10577                    BreakpointEditAction::Toggle,
10578                    cx,
10579                );
10580            }
10581        }
10582    }
10583
10584    pub fn edit_breakpoint_at_anchor(
10585        &mut self,
10586        breakpoint_position: Anchor,
10587        breakpoint: Breakpoint,
10588        edit_action: BreakpointEditAction,
10589        cx: &mut Context<Self>,
10590    ) {
10591        let Some(breakpoint_store) = &self.breakpoint_store else {
10592            return;
10593        };
10594
10595        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10596            if breakpoint_position == Anchor::min() {
10597                self.buffer()
10598                    .read(cx)
10599                    .excerpt_buffer_ids()
10600                    .into_iter()
10601                    .next()
10602            } else {
10603                None
10604            }
10605        }) else {
10606            return;
10607        };
10608
10609        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10610            return;
10611        };
10612
10613        breakpoint_store.update(cx, |breakpoint_store, cx| {
10614            breakpoint_store.toggle_breakpoint(
10615                buffer,
10616                BreakpointWithPosition {
10617                    position: breakpoint_position.text_anchor,
10618                    bp: breakpoint,
10619                },
10620                edit_action,
10621                cx,
10622            );
10623        });
10624
10625        cx.notify();
10626    }
10627
10628    #[cfg(any(test, feature = "test-support"))]
10629    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10630        self.breakpoint_store.clone()
10631    }
10632
10633    pub fn prepare_restore_change(
10634        &self,
10635        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10636        hunk: &MultiBufferDiffHunk,
10637        cx: &mut App,
10638    ) -> Option<()> {
10639        if hunk.is_created_file() {
10640            return None;
10641        }
10642        let buffer = self.buffer.read(cx);
10643        let diff = buffer.diff_for(hunk.buffer_id)?;
10644        let buffer = buffer.buffer(hunk.buffer_id)?;
10645        let buffer = buffer.read(cx);
10646        let original_text = diff
10647            .read(cx)
10648            .base_text()
10649            .as_rope()
10650            .slice(hunk.diff_base_byte_range.clone());
10651        let buffer_snapshot = buffer.snapshot();
10652        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10653        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10654            probe
10655                .0
10656                .start
10657                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10658                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10659        }) {
10660            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10661            Some(())
10662        } else {
10663            None
10664        }
10665    }
10666
10667    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10668        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10669    }
10670
10671    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10672        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10673    }
10674
10675    fn manipulate_lines<M>(
10676        &mut self,
10677        window: &mut Window,
10678        cx: &mut Context<Self>,
10679        mut manipulate: M,
10680    ) where
10681        M: FnMut(&str) -> LineManipulationResult,
10682    {
10683        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10684
10685        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10686        let buffer = self.buffer.read(cx).snapshot(cx);
10687
10688        let mut edits = Vec::new();
10689
10690        let selections = self.selections.all::<Point>(cx);
10691        let mut selections = selections.iter().peekable();
10692        let mut contiguous_row_selections = Vec::new();
10693        let mut new_selections = Vec::new();
10694        let mut added_lines = 0;
10695        let mut removed_lines = 0;
10696
10697        while let Some(selection) = selections.next() {
10698            let (start_row, end_row) = consume_contiguous_rows(
10699                &mut contiguous_row_selections,
10700                selection,
10701                &display_map,
10702                &mut selections,
10703            );
10704
10705            let start_point = Point::new(start_row.0, 0);
10706            let end_point = Point::new(
10707                end_row.previous_row().0,
10708                buffer.line_len(end_row.previous_row()),
10709            );
10710            let text = buffer
10711                .text_for_range(start_point..end_point)
10712                .collect::<String>();
10713
10714            let LineManipulationResult {
10715                new_text,
10716                line_count_before,
10717                line_count_after,
10718            } = manipulate(&text);
10719
10720            edits.push((start_point..end_point, new_text));
10721
10722            // Selections must change based on added and removed line count
10723            let start_row =
10724                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10725            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10726            new_selections.push(Selection {
10727                id: selection.id,
10728                start: start_row,
10729                end: end_row,
10730                goal: SelectionGoal::None,
10731                reversed: selection.reversed,
10732            });
10733
10734            if line_count_after > line_count_before {
10735                added_lines += line_count_after - line_count_before;
10736            } else if line_count_before > line_count_after {
10737                removed_lines += line_count_before - line_count_after;
10738            }
10739        }
10740
10741        self.transact(window, cx, |this, window, cx| {
10742            let buffer = this.buffer.update(cx, |buffer, cx| {
10743                buffer.edit(edits, None, cx);
10744                buffer.snapshot(cx)
10745            });
10746
10747            // Recalculate offsets on newly edited buffer
10748            let new_selections = new_selections
10749                .iter()
10750                .map(|s| {
10751                    let start_point = Point::new(s.start.0, 0);
10752                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10753                    Selection {
10754                        id: s.id,
10755                        start: buffer.point_to_offset(start_point),
10756                        end: buffer.point_to_offset(end_point),
10757                        goal: s.goal,
10758                        reversed: s.reversed,
10759                    }
10760                })
10761                .collect();
10762
10763            this.change_selections(Default::default(), window, cx, |s| {
10764                s.select(new_selections);
10765            });
10766
10767            this.request_autoscroll(Autoscroll::fit(), cx);
10768        });
10769    }
10770
10771    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10772        self.manipulate_text(window, cx, |text| {
10773            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10774            if has_upper_case_characters {
10775                text.to_lowercase()
10776            } else {
10777                text.to_uppercase()
10778            }
10779        })
10780    }
10781
10782    fn manipulate_immutable_lines<Fn>(
10783        &mut self,
10784        window: &mut Window,
10785        cx: &mut Context<Self>,
10786        mut callback: Fn,
10787    ) where
10788        Fn: FnMut(&mut Vec<&str>),
10789    {
10790        self.manipulate_lines(window, cx, |text| {
10791            let mut lines: Vec<&str> = text.split('\n').collect();
10792            let line_count_before = lines.len();
10793
10794            callback(&mut lines);
10795
10796            LineManipulationResult {
10797                new_text: lines.join("\n"),
10798                line_count_before,
10799                line_count_after: lines.len(),
10800            }
10801        });
10802    }
10803
10804    fn manipulate_mutable_lines<Fn>(
10805        &mut self,
10806        window: &mut Window,
10807        cx: &mut Context<Self>,
10808        mut callback: Fn,
10809    ) where
10810        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10811    {
10812        self.manipulate_lines(window, cx, |text| {
10813            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10814            let line_count_before = lines.len();
10815
10816            callback(&mut lines);
10817
10818            LineManipulationResult {
10819                new_text: lines.join("\n"),
10820                line_count_before,
10821                line_count_after: lines.len(),
10822            }
10823        });
10824    }
10825
10826    pub fn convert_indentation_to_spaces(
10827        &mut self,
10828        _: &ConvertIndentationToSpaces,
10829        window: &mut Window,
10830        cx: &mut Context<Self>,
10831    ) {
10832        let settings = self.buffer.read(cx).language_settings(cx);
10833        let tab_size = settings.tab_size.get() as usize;
10834
10835        self.manipulate_mutable_lines(window, cx, |lines| {
10836            // Allocates a reasonably sized scratch buffer once for the whole loop
10837            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10838            // Avoids recomputing spaces that could be inserted many times
10839            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10840                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10841                .collect();
10842
10843            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10844                let mut chars = line.as_ref().chars();
10845                let mut col = 0;
10846                let mut changed = false;
10847
10848                while let Some(ch) = chars.next() {
10849                    match ch {
10850                        ' ' => {
10851                            reindented_line.push(' ');
10852                            col += 1;
10853                        }
10854                        '\t' => {
10855                            // \t are converted to spaces depending on the current column
10856                            let spaces_len = tab_size - (col % tab_size);
10857                            reindented_line.extend(&space_cache[spaces_len - 1]);
10858                            col += spaces_len;
10859                            changed = true;
10860                        }
10861                        _ => {
10862                            // If we dont append before break, the character is consumed
10863                            reindented_line.push(ch);
10864                            break;
10865                        }
10866                    }
10867                }
10868
10869                if !changed {
10870                    reindented_line.clear();
10871                    continue;
10872                }
10873                // Append the rest of the line and replace old reference with new one
10874                reindented_line.extend(chars);
10875                *line = Cow::Owned(reindented_line.clone());
10876                reindented_line.clear();
10877            }
10878        });
10879    }
10880
10881    pub fn convert_indentation_to_tabs(
10882        &mut self,
10883        _: &ConvertIndentationToTabs,
10884        window: &mut Window,
10885        cx: &mut Context<Self>,
10886    ) {
10887        let settings = self.buffer.read(cx).language_settings(cx);
10888        let tab_size = settings.tab_size.get() as usize;
10889
10890        self.manipulate_mutable_lines(window, cx, |lines| {
10891            // Allocates a reasonably sized buffer once for the whole loop
10892            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10893            // Avoids recomputing spaces that could be inserted many times
10894            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10895                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10896                .collect();
10897
10898            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10899                let mut chars = line.chars();
10900                let mut spaces_count = 0;
10901                let mut first_non_indent_char = None;
10902                let mut changed = false;
10903
10904                while let Some(ch) = chars.next() {
10905                    match ch {
10906                        ' ' => {
10907                            // Keep track of spaces. Append \t when we reach tab_size
10908                            spaces_count += 1;
10909                            changed = true;
10910                            if spaces_count == tab_size {
10911                                reindented_line.push('\t');
10912                                spaces_count = 0;
10913                            }
10914                        }
10915                        '\t' => {
10916                            reindented_line.push('\t');
10917                            spaces_count = 0;
10918                        }
10919                        _ => {
10920                            // Dont append it yet, we might have remaining spaces
10921                            first_non_indent_char = Some(ch);
10922                            break;
10923                        }
10924                    }
10925                }
10926
10927                if !changed {
10928                    reindented_line.clear();
10929                    continue;
10930                }
10931                // Remaining spaces that didn't make a full tab stop
10932                if spaces_count > 0 {
10933                    reindented_line.extend(&space_cache[spaces_count - 1]);
10934                }
10935                // If we consume an extra character that was not indentation, add it back
10936                if let Some(extra_char) = first_non_indent_char {
10937                    reindented_line.push(extra_char);
10938                }
10939                // Append the rest of the line and replace old reference with new one
10940                reindented_line.extend(chars);
10941                *line = Cow::Owned(reindented_line.clone());
10942                reindented_line.clear();
10943            }
10944        });
10945    }
10946
10947    pub fn convert_to_upper_case(
10948        &mut self,
10949        _: &ConvertToUpperCase,
10950        window: &mut Window,
10951        cx: &mut Context<Self>,
10952    ) {
10953        self.manipulate_text(window, cx, |text| text.to_uppercase())
10954    }
10955
10956    pub fn convert_to_lower_case(
10957        &mut self,
10958        _: &ConvertToLowerCase,
10959        window: &mut Window,
10960        cx: &mut Context<Self>,
10961    ) {
10962        self.manipulate_text(window, cx, |text| text.to_lowercase())
10963    }
10964
10965    pub fn convert_to_title_case(
10966        &mut self,
10967        _: &ConvertToTitleCase,
10968        window: &mut Window,
10969        cx: &mut Context<Self>,
10970    ) {
10971        self.manipulate_text(window, cx, |text| {
10972            text.split('\n')
10973                .map(|line| line.to_case(Case::Title))
10974                .join("\n")
10975        })
10976    }
10977
10978    pub fn convert_to_snake_case(
10979        &mut self,
10980        _: &ConvertToSnakeCase,
10981        window: &mut Window,
10982        cx: &mut Context<Self>,
10983    ) {
10984        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10985    }
10986
10987    pub fn convert_to_kebab_case(
10988        &mut self,
10989        _: &ConvertToKebabCase,
10990        window: &mut Window,
10991        cx: &mut Context<Self>,
10992    ) {
10993        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10994    }
10995
10996    pub fn convert_to_upper_camel_case(
10997        &mut self,
10998        _: &ConvertToUpperCamelCase,
10999        window: &mut Window,
11000        cx: &mut Context<Self>,
11001    ) {
11002        self.manipulate_text(window, cx, |text| {
11003            text.split('\n')
11004                .map(|line| line.to_case(Case::UpperCamel))
11005                .join("\n")
11006        })
11007    }
11008
11009    pub fn convert_to_lower_camel_case(
11010        &mut self,
11011        _: &ConvertToLowerCamelCase,
11012        window: &mut Window,
11013        cx: &mut Context<Self>,
11014    ) {
11015        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11016    }
11017
11018    pub fn convert_to_opposite_case(
11019        &mut self,
11020        _: &ConvertToOppositeCase,
11021        window: &mut Window,
11022        cx: &mut Context<Self>,
11023    ) {
11024        self.manipulate_text(window, cx, |text| {
11025            text.chars()
11026                .fold(String::with_capacity(text.len()), |mut t, c| {
11027                    if c.is_uppercase() {
11028                        t.extend(c.to_lowercase());
11029                    } else {
11030                        t.extend(c.to_uppercase());
11031                    }
11032                    t
11033                })
11034        })
11035    }
11036
11037    pub fn convert_to_rot13(
11038        &mut self,
11039        _: &ConvertToRot13,
11040        window: &mut Window,
11041        cx: &mut Context<Self>,
11042    ) {
11043        self.manipulate_text(window, cx, |text| {
11044            text.chars()
11045                .map(|c| match c {
11046                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11047                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11048                    _ => c,
11049                })
11050                .collect()
11051        })
11052    }
11053
11054    pub fn convert_to_rot47(
11055        &mut self,
11056        _: &ConvertToRot47,
11057        window: &mut Window,
11058        cx: &mut Context<Self>,
11059    ) {
11060        self.manipulate_text(window, cx, |text| {
11061            text.chars()
11062                .map(|c| {
11063                    let code_point = c as u32;
11064                    if code_point >= 33 && code_point <= 126 {
11065                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11066                    }
11067                    c
11068                })
11069                .collect()
11070        })
11071    }
11072
11073    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11074    where
11075        Fn: FnMut(&str) -> String,
11076    {
11077        let buffer = self.buffer.read(cx).snapshot(cx);
11078
11079        let mut new_selections = Vec::new();
11080        let mut edits = Vec::new();
11081        let mut selection_adjustment = 0i32;
11082
11083        for selection in self.selections.all::<usize>(cx) {
11084            let selection_is_empty = selection.is_empty();
11085
11086            let (start, end) = if selection_is_empty {
11087                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11088                (word_range.start, word_range.end)
11089            } else {
11090                (selection.start, selection.end)
11091            };
11092
11093            let text = buffer.text_for_range(start..end).collect::<String>();
11094            let old_length = text.len() as i32;
11095            let text = callback(&text);
11096
11097            new_selections.push(Selection {
11098                start: (start as i32 - selection_adjustment) as usize,
11099                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11100                goal: SelectionGoal::None,
11101                ..selection
11102            });
11103
11104            selection_adjustment += old_length - text.len() as i32;
11105
11106            edits.push((start..end, text));
11107        }
11108
11109        self.transact(window, cx, |this, window, cx| {
11110            this.buffer.update(cx, |buffer, cx| {
11111                buffer.edit(edits, None, cx);
11112            });
11113
11114            this.change_selections(Default::default(), window, cx, |s| {
11115                s.select(new_selections);
11116            });
11117
11118            this.request_autoscroll(Autoscroll::fit(), cx);
11119        });
11120    }
11121
11122    pub fn move_selection_on_drop(
11123        &mut self,
11124        selection: &Selection<Anchor>,
11125        target: DisplayPoint,
11126        is_cut: bool,
11127        window: &mut Window,
11128        cx: &mut Context<Self>,
11129    ) {
11130        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11131        let buffer = &display_map.buffer_snapshot;
11132        let mut edits = Vec::new();
11133        let insert_point = display_map
11134            .clip_point(target, Bias::Left)
11135            .to_point(&display_map);
11136        let text = buffer
11137            .text_for_range(selection.start..selection.end)
11138            .collect::<String>();
11139        if is_cut {
11140            edits.push(((selection.start..selection.end), String::new()));
11141        }
11142        let insert_anchor = buffer.anchor_before(insert_point);
11143        edits.push(((insert_anchor..insert_anchor), text));
11144        let last_edit_start = insert_anchor.bias_left(buffer);
11145        let last_edit_end = insert_anchor.bias_right(buffer);
11146        self.transact(window, cx, |this, window, cx| {
11147            this.buffer.update(cx, |buffer, cx| {
11148                buffer.edit(edits, None, cx);
11149            });
11150            this.change_selections(Default::default(), window, cx, |s| {
11151                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11152            });
11153        });
11154    }
11155
11156    pub fn clear_selection_drag_state(&mut self) {
11157        self.selection_drag_state = SelectionDragState::None;
11158    }
11159
11160    pub fn duplicate(
11161        &mut self,
11162        upwards: bool,
11163        whole_lines: bool,
11164        window: &mut Window,
11165        cx: &mut Context<Self>,
11166    ) {
11167        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11168
11169        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11170        let buffer = &display_map.buffer_snapshot;
11171        let selections = self.selections.all::<Point>(cx);
11172
11173        let mut edits = Vec::new();
11174        let mut selections_iter = selections.iter().peekable();
11175        while let Some(selection) = selections_iter.next() {
11176            let mut rows = selection.spanned_rows(false, &display_map);
11177            // duplicate line-wise
11178            if whole_lines || selection.start == selection.end {
11179                // Avoid duplicating the same lines twice.
11180                while let Some(next_selection) = selections_iter.peek() {
11181                    let next_rows = next_selection.spanned_rows(false, &display_map);
11182                    if next_rows.start < rows.end {
11183                        rows.end = next_rows.end;
11184                        selections_iter.next().unwrap();
11185                    } else {
11186                        break;
11187                    }
11188                }
11189
11190                // Copy the text from the selected row region and splice it either at the start
11191                // or end of the region.
11192                let start = Point::new(rows.start.0, 0);
11193                let end = Point::new(
11194                    rows.end.previous_row().0,
11195                    buffer.line_len(rows.end.previous_row()),
11196                );
11197                let text = buffer
11198                    .text_for_range(start..end)
11199                    .chain(Some("\n"))
11200                    .collect::<String>();
11201                let insert_location = if upwards {
11202                    Point::new(rows.end.0, 0)
11203                } else {
11204                    start
11205                };
11206                edits.push((insert_location..insert_location, text));
11207            } else {
11208                // duplicate character-wise
11209                let start = selection.start;
11210                let end = selection.end;
11211                let text = buffer.text_for_range(start..end).collect::<String>();
11212                edits.push((selection.end..selection.end, text));
11213            }
11214        }
11215
11216        self.transact(window, cx, |this, _, cx| {
11217            this.buffer.update(cx, |buffer, cx| {
11218                buffer.edit(edits, None, cx);
11219            });
11220
11221            this.request_autoscroll(Autoscroll::fit(), cx);
11222        });
11223    }
11224
11225    pub fn duplicate_line_up(
11226        &mut self,
11227        _: &DuplicateLineUp,
11228        window: &mut Window,
11229        cx: &mut Context<Self>,
11230    ) {
11231        self.duplicate(true, true, window, cx);
11232    }
11233
11234    pub fn duplicate_line_down(
11235        &mut self,
11236        _: &DuplicateLineDown,
11237        window: &mut Window,
11238        cx: &mut Context<Self>,
11239    ) {
11240        self.duplicate(false, true, window, cx);
11241    }
11242
11243    pub fn duplicate_selection(
11244        &mut self,
11245        _: &DuplicateSelection,
11246        window: &mut Window,
11247        cx: &mut Context<Self>,
11248    ) {
11249        self.duplicate(false, false, window, cx);
11250    }
11251
11252    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11253        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11254        if self.mode.is_single_line() {
11255            cx.propagate();
11256            return;
11257        }
11258
11259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11260        let buffer = self.buffer.read(cx).snapshot(cx);
11261
11262        let mut edits = Vec::new();
11263        let mut unfold_ranges = Vec::new();
11264        let mut refold_creases = Vec::new();
11265
11266        let selections = self.selections.all::<Point>(cx);
11267        let mut selections = selections.iter().peekable();
11268        let mut contiguous_row_selections = Vec::new();
11269        let mut new_selections = Vec::new();
11270
11271        while let Some(selection) = selections.next() {
11272            // Find all the selections that span a contiguous row range
11273            let (start_row, end_row) = consume_contiguous_rows(
11274                &mut contiguous_row_selections,
11275                selection,
11276                &display_map,
11277                &mut selections,
11278            );
11279
11280            // Move the text spanned by the row range to be before the line preceding the row range
11281            if start_row.0 > 0 {
11282                let range_to_move = Point::new(
11283                    start_row.previous_row().0,
11284                    buffer.line_len(start_row.previous_row()),
11285                )
11286                    ..Point::new(
11287                        end_row.previous_row().0,
11288                        buffer.line_len(end_row.previous_row()),
11289                    );
11290                let insertion_point = display_map
11291                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11292                    .0;
11293
11294                // Don't move lines across excerpts
11295                if buffer
11296                    .excerpt_containing(insertion_point..range_to_move.end)
11297                    .is_some()
11298                {
11299                    let text = buffer
11300                        .text_for_range(range_to_move.clone())
11301                        .flat_map(|s| s.chars())
11302                        .skip(1)
11303                        .chain(['\n'])
11304                        .collect::<String>();
11305
11306                    edits.push((
11307                        buffer.anchor_after(range_to_move.start)
11308                            ..buffer.anchor_before(range_to_move.end),
11309                        String::new(),
11310                    ));
11311                    let insertion_anchor = buffer.anchor_after(insertion_point);
11312                    edits.push((insertion_anchor..insertion_anchor, text));
11313
11314                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11315
11316                    // Move selections up
11317                    new_selections.extend(contiguous_row_selections.drain(..).map(
11318                        |mut selection| {
11319                            selection.start.row -= row_delta;
11320                            selection.end.row -= row_delta;
11321                            selection
11322                        },
11323                    ));
11324
11325                    // Move folds up
11326                    unfold_ranges.push(range_to_move.clone());
11327                    for fold in display_map.folds_in_range(
11328                        buffer.anchor_before(range_to_move.start)
11329                            ..buffer.anchor_after(range_to_move.end),
11330                    ) {
11331                        let mut start = fold.range.start.to_point(&buffer);
11332                        let mut end = fold.range.end.to_point(&buffer);
11333                        start.row -= row_delta;
11334                        end.row -= row_delta;
11335                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11336                    }
11337                }
11338            }
11339
11340            // If we didn't move line(s), preserve the existing selections
11341            new_selections.append(&mut contiguous_row_selections);
11342        }
11343
11344        self.transact(window, cx, |this, window, cx| {
11345            this.unfold_ranges(&unfold_ranges, true, true, cx);
11346            this.buffer.update(cx, |buffer, cx| {
11347                for (range, text) in edits {
11348                    buffer.edit([(range, text)], None, cx);
11349                }
11350            });
11351            this.fold_creases(refold_creases, true, window, cx);
11352            this.change_selections(Default::default(), window, cx, |s| {
11353                s.select(new_selections);
11354            })
11355        });
11356    }
11357
11358    pub fn move_line_down(
11359        &mut self,
11360        _: &MoveLineDown,
11361        window: &mut Window,
11362        cx: &mut Context<Self>,
11363    ) {
11364        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11365        if self.mode.is_single_line() {
11366            cx.propagate();
11367            return;
11368        }
11369
11370        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11371        let buffer = self.buffer.read(cx).snapshot(cx);
11372
11373        let mut edits = Vec::new();
11374        let mut unfold_ranges = Vec::new();
11375        let mut refold_creases = Vec::new();
11376
11377        let selections = self.selections.all::<Point>(cx);
11378        let mut selections = selections.iter().peekable();
11379        let mut contiguous_row_selections = Vec::new();
11380        let mut new_selections = Vec::new();
11381
11382        while let Some(selection) = selections.next() {
11383            // Find all the selections that span a contiguous row range
11384            let (start_row, end_row) = consume_contiguous_rows(
11385                &mut contiguous_row_selections,
11386                selection,
11387                &display_map,
11388                &mut selections,
11389            );
11390
11391            // Move the text spanned by the row range to be after the last line of the row range
11392            if end_row.0 <= buffer.max_point().row {
11393                let range_to_move =
11394                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11395                let insertion_point = display_map
11396                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11397                    .0;
11398
11399                // Don't move lines across excerpt boundaries
11400                if buffer
11401                    .excerpt_containing(range_to_move.start..insertion_point)
11402                    .is_some()
11403                {
11404                    let mut text = String::from("\n");
11405                    text.extend(buffer.text_for_range(range_to_move.clone()));
11406                    text.pop(); // Drop trailing newline
11407                    edits.push((
11408                        buffer.anchor_after(range_to_move.start)
11409                            ..buffer.anchor_before(range_to_move.end),
11410                        String::new(),
11411                    ));
11412                    let insertion_anchor = buffer.anchor_after(insertion_point);
11413                    edits.push((insertion_anchor..insertion_anchor, text));
11414
11415                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11416
11417                    // Move selections down
11418                    new_selections.extend(contiguous_row_selections.drain(..).map(
11419                        |mut selection| {
11420                            selection.start.row += row_delta;
11421                            selection.end.row += row_delta;
11422                            selection
11423                        },
11424                    ));
11425
11426                    // Move folds down
11427                    unfold_ranges.push(range_to_move.clone());
11428                    for fold in display_map.folds_in_range(
11429                        buffer.anchor_before(range_to_move.start)
11430                            ..buffer.anchor_after(range_to_move.end),
11431                    ) {
11432                        let mut start = fold.range.start.to_point(&buffer);
11433                        let mut end = fold.range.end.to_point(&buffer);
11434                        start.row += row_delta;
11435                        end.row += row_delta;
11436                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11437                    }
11438                }
11439            }
11440
11441            // If we didn't move line(s), preserve the existing selections
11442            new_selections.append(&mut contiguous_row_selections);
11443        }
11444
11445        self.transact(window, cx, |this, window, cx| {
11446            this.unfold_ranges(&unfold_ranges, true, true, cx);
11447            this.buffer.update(cx, |buffer, cx| {
11448                for (range, text) in edits {
11449                    buffer.edit([(range, text)], None, cx);
11450                }
11451            });
11452            this.fold_creases(refold_creases, true, window, cx);
11453            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11454        });
11455    }
11456
11457    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11459        let text_layout_details = &self.text_layout_details(window);
11460        self.transact(window, cx, |this, window, cx| {
11461            let edits = this.change_selections(Default::default(), window, cx, |s| {
11462                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11463                s.move_with(|display_map, selection| {
11464                    if !selection.is_empty() {
11465                        return;
11466                    }
11467
11468                    let mut head = selection.head();
11469                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11470                    if head.column() == display_map.line_len(head.row()) {
11471                        transpose_offset = display_map
11472                            .buffer_snapshot
11473                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11474                    }
11475
11476                    if transpose_offset == 0 {
11477                        return;
11478                    }
11479
11480                    *head.column_mut() += 1;
11481                    head = display_map.clip_point(head, Bias::Right);
11482                    let goal = SelectionGoal::HorizontalPosition(
11483                        display_map
11484                            .x_for_display_point(head, text_layout_details)
11485                            .into(),
11486                    );
11487                    selection.collapse_to(head, goal);
11488
11489                    let transpose_start = display_map
11490                        .buffer_snapshot
11491                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11492                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11493                        let transpose_end = display_map
11494                            .buffer_snapshot
11495                            .clip_offset(transpose_offset + 1, Bias::Right);
11496                        if let Some(ch) =
11497                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11498                        {
11499                            edits.push((transpose_start..transpose_offset, String::new()));
11500                            edits.push((transpose_end..transpose_end, ch.to_string()));
11501                        }
11502                    }
11503                });
11504                edits
11505            });
11506            this.buffer
11507                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11508            let selections = this.selections.all::<usize>(cx);
11509            this.change_selections(Default::default(), window, cx, |s| {
11510                s.select(selections);
11511            });
11512        });
11513    }
11514
11515    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11516        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11517        if self.mode.is_single_line() {
11518            cx.propagate();
11519            return;
11520        }
11521
11522        self.rewrap_impl(RewrapOptions::default(), cx)
11523    }
11524
11525    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11526        let buffer = self.buffer.read(cx).snapshot(cx);
11527        let selections = self.selections.all::<Point>(cx);
11528
11529        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11530        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11531            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11532                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11533                .peekable();
11534
11535            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11536                row
11537            } else {
11538                return Vec::new();
11539            };
11540
11541            let language_settings = buffer.language_settings_at(selection.head(), cx);
11542            let language_scope = buffer.language_scope_at(selection.head());
11543
11544            let mut ranges = Vec::new();
11545            let mut current_range_start = first_row;
11546            let from_empty_selection = selection.is_empty();
11547
11548            let mut prev_row = first_row;
11549            let mut prev_indent = buffer.indent_size_for_line(MultiBufferRow(first_row));
11550            let mut prev_comment_prefix = if let Some(language_scope) = &language_scope {
11551                let indent = buffer.indent_size_for_line(MultiBufferRow(first_row));
11552                let indent_end = Point::new(first_row, indent.len);
11553                language_scope
11554                    .line_comment_prefixes()
11555                    .iter()
11556                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11557                    .cloned()
11558            } else {
11559                None
11560            };
11561
11562            for row in non_blank_rows_iter.skip(1) {
11563                let has_paragraph_break = row > prev_row + 1;
11564
11565                let row_indent = buffer.indent_size_for_line(MultiBufferRow(row));
11566                let row_comment_prefix = if let Some(language_scope) = &language_scope {
11567                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11568                    let indent_end = Point::new(row, indent.len);
11569                    language_scope
11570                        .line_comment_prefixes()
11571                        .iter()
11572                        .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11573                        .cloned()
11574                } else {
11575                    None
11576                };
11577
11578                let has_boundary_change =
11579                    row_indent != prev_indent || row_comment_prefix != prev_comment_prefix;
11580
11581                if has_paragraph_break || has_boundary_change {
11582                    ranges.push((
11583                        language_settings.clone(),
11584                        Point::new(current_range_start, 0)
11585                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11586                        prev_indent,
11587                        prev_comment_prefix.clone(),
11588                        from_empty_selection,
11589                    ));
11590                    current_range_start = row;
11591                }
11592
11593                prev_row = row;
11594                prev_indent = row_indent;
11595                prev_comment_prefix = row_comment_prefix;
11596            }
11597
11598            ranges.push((
11599                language_settings.clone(),
11600                Point::new(current_range_start, 0)
11601                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11602                prev_indent,
11603                prev_comment_prefix,
11604                from_empty_selection,
11605            ));
11606
11607            ranges
11608        });
11609
11610        let mut edits = Vec::new();
11611        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11612
11613        for (language_settings, wrap_range, indent_size, comment_prefix, from_empty_selection) in
11614            wrap_ranges
11615        {
11616            let mut start_row = wrap_range.start.row;
11617            let mut end_row = wrap_range.end.row;
11618
11619            // Skip selections that overlap with a range that has already been rewrapped.
11620            let selection_range = start_row..end_row;
11621            if rewrapped_row_ranges
11622                .iter()
11623                .any(|range| range.overlaps(&selection_range))
11624            {
11625                continue;
11626            }
11627
11628            let tab_size = language_settings.tab_size;
11629
11630            let mut line_prefix = indent_size.chars().collect::<String>();
11631            let mut inside_comment = false;
11632            if let Some(prefix) = &comment_prefix {
11633                line_prefix.push_str(prefix);
11634                inside_comment = true;
11635            }
11636
11637            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11638                RewrapBehavior::InComments => inside_comment,
11639                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11640                RewrapBehavior::Anywhere => true,
11641            };
11642
11643            let should_rewrap = options.override_language_settings
11644                || allow_rewrap_based_on_language
11645                || self.hard_wrap.is_some();
11646            if !should_rewrap {
11647                continue;
11648            }
11649
11650            if from_empty_selection {
11651                'expand_upwards: while start_row > 0 {
11652                    let prev_row = start_row - 1;
11653                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11654                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11655                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11656                    {
11657                        start_row = prev_row;
11658                    } else {
11659                        break 'expand_upwards;
11660                    }
11661                }
11662
11663                'expand_downwards: while end_row < buffer.max_point().row {
11664                    let next_row = end_row + 1;
11665                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11666                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11667                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11668                    {
11669                        end_row = next_row;
11670                    } else {
11671                        break 'expand_downwards;
11672                    }
11673                }
11674            }
11675
11676            let start = Point::new(start_row, 0);
11677            let start_offset = start.to_offset(&buffer);
11678            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11679            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11680            let Some(lines_without_prefixes) = selection_text
11681                .lines()
11682                .map(|line| {
11683                    line.strip_prefix(&line_prefix)
11684                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11685                        .with_context(|| {
11686                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11687                        })
11688                })
11689                .collect::<Result<Vec<_>, _>>()
11690                .log_err()
11691            else {
11692                continue;
11693            };
11694
11695            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11696                buffer
11697                    .language_settings_at(Point::new(start_row, 0), cx)
11698                    .preferred_line_length as usize
11699            });
11700            let wrapped_text = wrap_with_prefix(
11701                line_prefix,
11702                lines_without_prefixes.join("\n"),
11703                wrap_column,
11704                tab_size,
11705                options.preserve_existing_whitespace,
11706            );
11707
11708            // TODO: should always use char-based diff while still supporting cursor behavior that
11709            // matches vim.
11710            let mut diff_options = DiffOptions::default();
11711            if options.override_language_settings {
11712                diff_options.max_word_diff_len = 0;
11713                diff_options.max_word_diff_line_count = 0;
11714            } else {
11715                diff_options.max_word_diff_len = usize::MAX;
11716                diff_options.max_word_diff_line_count = usize::MAX;
11717            }
11718
11719            for (old_range, new_text) in
11720                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11721            {
11722                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11723                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11724                edits.push((edit_start..edit_end, new_text));
11725            }
11726
11727            rewrapped_row_ranges.push(start_row..=end_row);
11728        }
11729
11730        self.buffer
11731            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11732    }
11733
11734    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11735        let mut text = String::new();
11736        let buffer = self.buffer.read(cx).snapshot(cx);
11737        let mut selections = self.selections.all::<Point>(cx);
11738        let mut clipboard_selections = Vec::with_capacity(selections.len());
11739        {
11740            let max_point = buffer.max_point();
11741            let mut is_first = true;
11742            for selection in &mut selections {
11743                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11744                if is_entire_line {
11745                    selection.start = Point::new(selection.start.row, 0);
11746                    if !selection.is_empty() && selection.end.column == 0 {
11747                        selection.end = cmp::min(max_point, selection.end);
11748                    } else {
11749                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11750                    }
11751                    selection.goal = SelectionGoal::None;
11752                }
11753                if is_first {
11754                    is_first = false;
11755                } else {
11756                    text += "\n";
11757                }
11758                let mut len = 0;
11759                for chunk in buffer.text_for_range(selection.start..selection.end) {
11760                    text.push_str(chunk);
11761                    len += chunk.len();
11762                }
11763                clipboard_selections.push(ClipboardSelection {
11764                    len,
11765                    is_entire_line,
11766                    first_line_indent: buffer
11767                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11768                        .len,
11769                });
11770            }
11771        }
11772
11773        self.transact(window, cx, |this, window, cx| {
11774            this.change_selections(Default::default(), window, cx, |s| {
11775                s.select(selections);
11776            });
11777            this.insert("", window, cx);
11778        });
11779        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11780    }
11781
11782    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11783        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11784        let item = self.cut_common(window, cx);
11785        cx.write_to_clipboard(item);
11786    }
11787
11788    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11789        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11790        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11791            s.move_with(|snapshot, sel| {
11792                if sel.is_empty() {
11793                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11794                }
11795            });
11796        });
11797        let item = self.cut_common(window, cx);
11798        cx.set_global(KillRing(item))
11799    }
11800
11801    pub fn kill_ring_yank(
11802        &mut self,
11803        _: &KillRingYank,
11804        window: &mut Window,
11805        cx: &mut Context<Self>,
11806    ) {
11807        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11808        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11809            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11810                (kill_ring.text().to_string(), kill_ring.metadata_json())
11811            } else {
11812                return;
11813            }
11814        } else {
11815            return;
11816        };
11817        self.do_paste(&text, metadata, false, window, cx);
11818    }
11819
11820    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11821        self.do_copy(true, cx);
11822    }
11823
11824    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11825        self.do_copy(false, cx);
11826    }
11827
11828    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11829        let selections = self.selections.all::<Point>(cx);
11830        let buffer = self.buffer.read(cx).read(cx);
11831        let mut text = String::new();
11832
11833        let mut clipboard_selections = Vec::with_capacity(selections.len());
11834        {
11835            let max_point = buffer.max_point();
11836            let mut is_first = true;
11837            for selection in &selections {
11838                let mut start = selection.start;
11839                let mut end = selection.end;
11840                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11841                if is_entire_line {
11842                    start = Point::new(start.row, 0);
11843                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11844                }
11845
11846                let mut trimmed_selections = Vec::new();
11847                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11848                    let row = MultiBufferRow(start.row);
11849                    let first_indent = buffer.indent_size_for_line(row);
11850                    if first_indent.len == 0 || start.column > first_indent.len {
11851                        trimmed_selections.push(start..end);
11852                    } else {
11853                        trimmed_selections.push(
11854                            Point::new(row.0, first_indent.len)
11855                                ..Point::new(row.0, buffer.line_len(row)),
11856                        );
11857                        for row in start.row + 1..=end.row {
11858                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11859                            if row == end.row {
11860                                line_len = end.column;
11861                            }
11862                            if line_len == 0 {
11863                                trimmed_selections
11864                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11865                                continue;
11866                            }
11867                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11868                            if row_indent_size.len >= first_indent.len {
11869                                trimmed_selections.push(
11870                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11871                                );
11872                            } else {
11873                                trimmed_selections.clear();
11874                                trimmed_selections.push(start..end);
11875                                break;
11876                            }
11877                        }
11878                    }
11879                } else {
11880                    trimmed_selections.push(start..end);
11881                }
11882
11883                for trimmed_range in trimmed_selections {
11884                    if is_first {
11885                        is_first = false;
11886                    } else {
11887                        text += "\n";
11888                    }
11889                    let mut len = 0;
11890                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11891                        text.push_str(chunk);
11892                        len += chunk.len();
11893                    }
11894                    clipboard_selections.push(ClipboardSelection {
11895                        len,
11896                        is_entire_line,
11897                        first_line_indent: buffer
11898                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11899                            .len,
11900                    });
11901                }
11902            }
11903        }
11904
11905        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11906            text,
11907            clipboard_selections,
11908        ));
11909    }
11910
11911    pub fn do_paste(
11912        &mut self,
11913        text: &String,
11914        clipboard_selections: Option<Vec<ClipboardSelection>>,
11915        handle_entire_lines: bool,
11916        window: &mut Window,
11917        cx: &mut Context<Self>,
11918    ) {
11919        if self.read_only(cx) {
11920            return;
11921        }
11922
11923        let clipboard_text = Cow::Borrowed(text);
11924
11925        self.transact(window, cx, |this, window, cx| {
11926            if let Some(mut clipboard_selections) = clipboard_selections {
11927                let old_selections = this.selections.all::<usize>(cx);
11928                let all_selections_were_entire_line =
11929                    clipboard_selections.iter().all(|s| s.is_entire_line);
11930                let first_selection_indent_column =
11931                    clipboard_selections.first().map(|s| s.first_line_indent);
11932                if clipboard_selections.len() != old_selections.len() {
11933                    clipboard_selections.drain(..);
11934                }
11935                let cursor_offset = this.selections.last::<usize>(cx).head();
11936                let mut auto_indent_on_paste = true;
11937
11938                this.buffer.update(cx, |buffer, cx| {
11939                    let snapshot = buffer.read(cx);
11940                    auto_indent_on_paste = snapshot
11941                        .language_settings_at(cursor_offset, cx)
11942                        .auto_indent_on_paste;
11943
11944                    let mut start_offset = 0;
11945                    let mut edits = Vec::new();
11946                    let mut original_indent_columns = Vec::new();
11947                    for (ix, selection) in old_selections.iter().enumerate() {
11948                        let to_insert;
11949                        let entire_line;
11950                        let original_indent_column;
11951                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11952                            let end_offset = start_offset + clipboard_selection.len;
11953                            to_insert = &clipboard_text[start_offset..end_offset];
11954                            entire_line = clipboard_selection.is_entire_line;
11955                            start_offset = end_offset + 1;
11956                            original_indent_column = Some(clipboard_selection.first_line_indent);
11957                        } else {
11958                            to_insert = clipboard_text.as_str();
11959                            entire_line = all_selections_were_entire_line;
11960                            original_indent_column = first_selection_indent_column
11961                        }
11962
11963                        // If the corresponding selection was empty when this slice of the
11964                        // clipboard text was written, then the entire line containing the
11965                        // selection was copied. If this selection is also currently empty,
11966                        // then paste the line before the current line of the buffer.
11967                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11968                            let column = selection.start.to_point(&snapshot).column as usize;
11969                            let line_start = selection.start - column;
11970                            line_start..line_start
11971                        } else {
11972                            selection.range()
11973                        };
11974
11975                        edits.push((range, to_insert));
11976                        original_indent_columns.push(original_indent_column);
11977                    }
11978                    drop(snapshot);
11979
11980                    buffer.edit(
11981                        edits,
11982                        if auto_indent_on_paste {
11983                            Some(AutoindentMode::Block {
11984                                original_indent_columns,
11985                            })
11986                        } else {
11987                            None
11988                        },
11989                        cx,
11990                    );
11991                });
11992
11993                let selections = this.selections.all::<usize>(cx);
11994                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11995            } else {
11996                this.insert(&clipboard_text, window, cx);
11997            }
11998        });
11999    }
12000
12001    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12003        if let Some(item) = cx.read_from_clipboard() {
12004            let entries = item.entries();
12005
12006            match entries.first() {
12007                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12008                // of all the pasted entries.
12009                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12010                    .do_paste(
12011                        clipboard_string.text(),
12012                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12013                        true,
12014                        window,
12015                        cx,
12016                    ),
12017                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12018            }
12019        }
12020    }
12021
12022    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12023        if self.read_only(cx) {
12024            return;
12025        }
12026
12027        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12028
12029        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12030            if let Some((selections, _)) =
12031                self.selection_history.transaction(transaction_id).cloned()
12032            {
12033                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12034                    s.select_anchors(selections.to_vec());
12035                });
12036            } else {
12037                log::error!(
12038                    "No entry in selection_history found for undo. \
12039                     This may correspond to a bug where undo does not update the selection. \
12040                     If this is occurring, please add details to \
12041                     https://github.com/zed-industries/zed/issues/22692"
12042                );
12043            }
12044            self.request_autoscroll(Autoscroll::fit(), cx);
12045            self.unmark_text(window, cx);
12046            self.refresh_inline_completion(true, false, window, cx);
12047            cx.emit(EditorEvent::Edited { transaction_id });
12048            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12049        }
12050    }
12051
12052    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12053        if self.read_only(cx) {
12054            return;
12055        }
12056
12057        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12058
12059        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12060            if let Some((_, Some(selections))) =
12061                self.selection_history.transaction(transaction_id).cloned()
12062            {
12063                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12064                    s.select_anchors(selections.to_vec());
12065                });
12066            } else {
12067                log::error!(
12068                    "No entry in selection_history found for redo. \
12069                     This may correspond to a bug where undo does not update the selection. \
12070                     If this is occurring, please add details to \
12071                     https://github.com/zed-industries/zed/issues/22692"
12072                );
12073            }
12074            self.request_autoscroll(Autoscroll::fit(), cx);
12075            self.unmark_text(window, cx);
12076            self.refresh_inline_completion(true, false, window, cx);
12077            cx.emit(EditorEvent::Edited { transaction_id });
12078        }
12079    }
12080
12081    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12082        self.buffer
12083            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12084    }
12085
12086    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12087        self.buffer
12088            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12089    }
12090
12091    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12092        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12093        self.change_selections(Default::default(), window, cx, |s| {
12094            s.move_with(|map, selection| {
12095                let cursor = if selection.is_empty() {
12096                    movement::left(map, selection.start)
12097                } else {
12098                    selection.start
12099                };
12100                selection.collapse_to(cursor, SelectionGoal::None);
12101            });
12102        })
12103    }
12104
12105    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12106        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12107        self.change_selections(Default::default(), window, cx, |s| {
12108            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12109        })
12110    }
12111
12112    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12113        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12114        self.change_selections(Default::default(), window, cx, |s| {
12115            s.move_with(|map, selection| {
12116                let cursor = if selection.is_empty() {
12117                    movement::right(map, selection.end)
12118                } else {
12119                    selection.end
12120                };
12121                selection.collapse_to(cursor, SelectionGoal::None)
12122            });
12123        })
12124    }
12125
12126    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12127        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12128        self.change_selections(Default::default(), window, cx, |s| {
12129            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12130        })
12131    }
12132
12133    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12134        if self.take_rename(true, window, cx).is_some() {
12135            return;
12136        }
12137
12138        if self.mode.is_single_line() {
12139            cx.propagate();
12140            return;
12141        }
12142
12143        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12144
12145        let text_layout_details = &self.text_layout_details(window);
12146        let selection_count = self.selections.count();
12147        let first_selection = self.selections.first_anchor();
12148
12149        self.change_selections(Default::default(), window, cx, |s| {
12150            s.move_with(|map, selection| {
12151                if !selection.is_empty() {
12152                    selection.goal = SelectionGoal::None;
12153                }
12154                let (cursor, goal) = movement::up(
12155                    map,
12156                    selection.start,
12157                    selection.goal,
12158                    false,
12159                    text_layout_details,
12160                );
12161                selection.collapse_to(cursor, goal);
12162            });
12163        });
12164
12165        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12166        {
12167            cx.propagate();
12168        }
12169    }
12170
12171    pub fn move_up_by_lines(
12172        &mut self,
12173        action: &MoveUpByLines,
12174        window: &mut Window,
12175        cx: &mut Context<Self>,
12176    ) {
12177        if self.take_rename(true, window, cx).is_some() {
12178            return;
12179        }
12180
12181        if self.mode.is_single_line() {
12182            cx.propagate();
12183            return;
12184        }
12185
12186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12187
12188        let text_layout_details = &self.text_layout_details(window);
12189
12190        self.change_selections(Default::default(), window, cx, |s| {
12191            s.move_with(|map, selection| {
12192                if !selection.is_empty() {
12193                    selection.goal = SelectionGoal::None;
12194                }
12195                let (cursor, goal) = movement::up_by_rows(
12196                    map,
12197                    selection.start,
12198                    action.lines,
12199                    selection.goal,
12200                    false,
12201                    text_layout_details,
12202                );
12203                selection.collapse_to(cursor, goal);
12204            });
12205        })
12206    }
12207
12208    pub fn move_down_by_lines(
12209        &mut self,
12210        action: &MoveDownByLines,
12211        window: &mut Window,
12212        cx: &mut Context<Self>,
12213    ) {
12214        if self.take_rename(true, window, cx).is_some() {
12215            return;
12216        }
12217
12218        if self.mode.is_single_line() {
12219            cx.propagate();
12220            return;
12221        }
12222
12223        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12224
12225        let text_layout_details = &self.text_layout_details(window);
12226
12227        self.change_selections(Default::default(), window, cx, |s| {
12228            s.move_with(|map, selection| {
12229                if !selection.is_empty() {
12230                    selection.goal = SelectionGoal::None;
12231                }
12232                let (cursor, goal) = movement::down_by_rows(
12233                    map,
12234                    selection.start,
12235                    action.lines,
12236                    selection.goal,
12237                    false,
12238                    text_layout_details,
12239                );
12240                selection.collapse_to(cursor, goal);
12241            });
12242        })
12243    }
12244
12245    pub fn select_down_by_lines(
12246        &mut self,
12247        action: &SelectDownByLines,
12248        window: &mut Window,
12249        cx: &mut Context<Self>,
12250    ) {
12251        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12252        let text_layout_details = &self.text_layout_details(window);
12253        self.change_selections(Default::default(), window, cx, |s| {
12254            s.move_heads_with(|map, head, goal| {
12255                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12256            })
12257        })
12258    }
12259
12260    pub fn select_up_by_lines(
12261        &mut self,
12262        action: &SelectUpByLines,
12263        window: &mut Window,
12264        cx: &mut Context<Self>,
12265    ) {
12266        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12267        let text_layout_details = &self.text_layout_details(window);
12268        self.change_selections(Default::default(), window, cx, |s| {
12269            s.move_heads_with(|map, head, goal| {
12270                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12271            })
12272        })
12273    }
12274
12275    pub fn select_page_up(
12276        &mut self,
12277        _: &SelectPageUp,
12278        window: &mut Window,
12279        cx: &mut Context<Self>,
12280    ) {
12281        let Some(row_count) = self.visible_row_count() else {
12282            return;
12283        };
12284
12285        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12286
12287        let text_layout_details = &self.text_layout_details(window);
12288
12289        self.change_selections(Default::default(), window, cx, |s| {
12290            s.move_heads_with(|map, head, goal| {
12291                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12292            })
12293        })
12294    }
12295
12296    pub fn move_page_up(
12297        &mut self,
12298        action: &MovePageUp,
12299        window: &mut Window,
12300        cx: &mut Context<Self>,
12301    ) {
12302        if self.take_rename(true, window, cx).is_some() {
12303            return;
12304        }
12305
12306        if self
12307            .context_menu
12308            .borrow_mut()
12309            .as_mut()
12310            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12311            .unwrap_or(false)
12312        {
12313            return;
12314        }
12315
12316        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12317            cx.propagate();
12318            return;
12319        }
12320
12321        let Some(row_count) = self.visible_row_count() else {
12322            return;
12323        };
12324
12325        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12326
12327        let effects = if action.center_cursor {
12328            SelectionEffects::scroll(Autoscroll::center())
12329        } else {
12330            SelectionEffects::default()
12331        };
12332
12333        let text_layout_details = &self.text_layout_details(window);
12334
12335        self.change_selections(effects, window, cx, |s| {
12336            s.move_with(|map, selection| {
12337                if !selection.is_empty() {
12338                    selection.goal = SelectionGoal::None;
12339                }
12340                let (cursor, goal) = movement::up_by_rows(
12341                    map,
12342                    selection.end,
12343                    row_count,
12344                    selection.goal,
12345                    false,
12346                    text_layout_details,
12347                );
12348                selection.collapse_to(cursor, goal);
12349            });
12350        });
12351    }
12352
12353    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12354        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12355        let text_layout_details = &self.text_layout_details(window);
12356        self.change_selections(Default::default(), window, cx, |s| {
12357            s.move_heads_with(|map, head, goal| {
12358                movement::up(map, head, goal, false, text_layout_details)
12359            })
12360        })
12361    }
12362
12363    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12364        self.take_rename(true, window, cx);
12365
12366        if self.mode.is_single_line() {
12367            cx.propagate();
12368            return;
12369        }
12370
12371        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12372
12373        let text_layout_details = &self.text_layout_details(window);
12374        let selection_count = self.selections.count();
12375        let first_selection = self.selections.first_anchor();
12376
12377        self.change_selections(Default::default(), window, cx, |s| {
12378            s.move_with(|map, selection| {
12379                if !selection.is_empty() {
12380                    selection.goal = SelectionGoal::None;
12381                }
12382                let (cursor, goal) = movement::down(
12383                    map,
12384                    selection.end,
12385                    selection.goal,
12386                    false,
12387                    text_layout_details,
12388                );
12389                selection.collapse_to(cursor, goal);
12390            });
12391        });
12392
12393        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12394        {
12395            cx.propagate();
12396        }
12397    }
12398
12399    pub fn select_page_down(
12400        &mut self,
12401        _: &SelectPageDown,
12402        window: &mut Window,
12403        cx: &mut Context<Self>,
12404    ) {
12405        let Some(row_count) = self.visible_row_count() else {
12406            return;
12407        };
12408
12409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12410
12411        let text_layout_details = &self.text_layout_details(window);
12412
12413        self.change_selections(Default::default(), window, cx, |s| {
12414            s.move_heads_with(|map, head, goal| {
12415                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12416            })
12417        })
12418    }
12419
12420    pub fn move_page_down(
12421        &mut self,
12422        action: &MovePageDown,
12423        window: &mut Window,
12424        cx: &mut Context<Self>,
12425    ) {
12426        if self.take_rename(true, window, cx).is_some() {
12427            return;
12428        }
12429
12430        if self
12431            .context_menu
12432            .borrow_mut()
12433            .as_mut()
12434            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12435            .unwrap_or(false)
12436        {
12437            return;
12438        }
12439
12440        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12441            cx.propagate();
12442            return;
12443        }
12444
12445        let Some(row_count) = self.visible_row_count() else {
12446            return;
12447        };
12448
12449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12450
12451        let effects = if action.center_cursor {
12452            SelectionEffects::scroll(Autoscroll::center())
12453        } else {
12454            SelectionEffects::default()
12455        };
12456
12457        let text_layout_details = &self.text_layout_details(window);
12458        self.change_selections(effects, window, cx, |s| {
12459            s.move_with(|map, selection| {
12460                if !selection.is_empty() {
12461                    selection.goal = SelectionGoal::None;
12462                }
12463                let (cursor, goal) = movement::down_by_rows(
12464                    map,
12465                    selection.end,
12466                    row_count,
12467                    selection.goal,
12468                    false,
12469                    text_layout_details,
12470                );
12471                selection.collapse_to(cursor, goal);
12472            });
12473        });
12474    }
12475
12476    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12477        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12478        let text_layout_details = &self.text_layout_details(window);
12479        self.change_selections(Default::default(), window, cx, |s| {
12480            s.move_heads_with(|map, head, goal| {
12481                movement::down(map, head, goal, false, text_layout_details)
12482            })
12483        });
12484    }
12485
12486    pub fn context_menu_first(
12487        &mut self,
12488        _: &ContextMenuFirst,
12489        window: &mut Window,
12490        cx: &mut Context<Self>,
12491    ) {
12492        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12493            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12494        }
12495    }
12496
12497    pub fn context_menu_prev(
12498        &mut self,
12499        _: &ContextMenuPrevious,
12500        window: &mut Window,
12501        cx: &mut Context<Self>,
12502    ) {
12503        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12504            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12505        }
12506    }
12507
12508    pub fn context_menu_next(
12509        &mut self,
12510        _: &ContextMenuNext,
12511        window: &mut Window,
12512        cx: &mut Context<Self>,
12513    ) {
12514        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12515            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12516        }
12517    }
12518
12519    pub fn context_menu_last(
12520        &mut self,
12521        _: &ContextMenuLast,
12522        window: &mut Window,
12523        cx: &mut Context<Self>,
12524    ) {
12525        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12526            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12527        }
12528    }
12529
12530    pub fn move_to_previous_word_start(
12531        &mut self,
12532        _: &MoveToPreviousWordStart,
12533        window: &mut Window,
12534        cx: &mut Context<Self>,
12535    ) {
12536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12537        self.change_selections(Default::default(), window, cx, |s| {
12538            s.move_cursors_with(|map, head, _| {
12539                (
12540                    movement::previous_word_start(map, head),
12541                    SelectionGoal::None,
12542                )
12543            });
12544        })
12545    }
12546
12547    pub fn move_to_previous_subword_start(
12548        &mut self,
12549        _: &MoveToPreviousSubwordStart,
12550        window: &mut Window,
12551        cx: &mut Context<Self>,
12552    ) {
12553        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12554        self.change_selections(Default::default(), window, cx, |s| {
12555            s.move_cursors_with(|map, head, _| {
12556                (
12557                    movement::previous_subword_start(map, head),
12558                    SelectionGoal::None,
12559                )
12560            });
12561        })
12562    }
12563
12564    pub fn select_to_previous_word_start(
12565        &mut self,
12566        _: &SelectToPreviousWordStart,
12567        window: &mut Window,
12568        cx: &mut Context<Self>,
12569    ) {
12570        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12571        self.change_selections(Default::default(), window, cx, |s| {
12572            s.move_heads_with(|map, head, _| {
12573                (
12574                    movement::previous_word_start(map, head),
12575                    SelectionGoal::None,
12576                )
12577            });
12578        })
12579    }
12580
12581    pub fn select_to_previous_subword_start(
12582        &mut self,
12583        _: &SelectToPreviousSubwordStart,
12584        window: &mut Window,
12585        cx: &mut Context<Self>,
12586    ) {
12587        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12588        self.change_selections(Default::default(), window, cx, |s| {
12589            s.move_heads_with(|map, head, _| {
12590                (
12591                    movement::previous_subword_start(map, head),
12592                    SelectionGoal::None,
12593                )
12594            });
12595        })
12596    }
12597
12598    pub fn delete_to_previous_word_start(
12599        &mut self,
12600        action: &DeleteToPreviousWordStart,
12601        window: &mut Window,
12602        cx: &mut Context<Self>,
12603    ) {
12604        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12605        self.transact(window, cx, |this, window, cx| {
12606            this.select_autoclose_pair(window, cx);
12607            this.change_selections(Default::default(), window, cx, |s| {
12608                s.move_with(|map, selection| {
12609                    if selection.is_empty() {
12610                        let cursor = if action.ignore_newlines {
12611                            movement::previous_word_start(map, selection.head())
12612                        } else {
12613                            movement::previous_word_start_or_newline(map, selection.head())
12614                        };
12615                        selection.set_head(cursor, SelectionGoal::None);
12616                    }
12617                });
12618            });
12619            this.insert("", window, cx);
12620        });
12621    }
12622
12623    pub fn delete_to_previous_subword_start(
12624        &mut self,
12625        _: &DeleteToPreviousSubwordStart,
12626        window: &mut Window,
12627        cx: &mut Context<Self>,
12628    ) {
12629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12630        self.transact(window, cx, |this, window, cx| {
12631            this.select_autoclose_pair(window, cx);
12632            this.change_selections(Default::default(), window, cx, |s| {
12633                s.move_with(|map, selection| {
12634                    if selection.is_empty() {
12635                        let cursor = movement::previous_subword_start(map, selection.head());
12636                        selection.set_head(cursor, SelectionGoal::None);
12637                    }
12638                });
12639            });
12640            this.insert("", window, cx);
12641        });
12642    }
12643
12644    pub fn move_to_next_word_end(
12645        &mut self,
12646        _: &MoveToNextWordEnd,
12647        window: &mut Window,
12648        cx: &mut Context<Self>,
12649    ) {
12650        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12651        self.change_selections(Default::default(), window, cx, |s| {
12652            s.move_cursors_with(|map, head, _| {
12653                (movement::next_word_end(map, head), SelectionGoal::None)
12654            });
12655        })
12656    }
12657
12658    pub fn move_to_next_subword_end(
12659        &mut self,
12660        _: &MoveToNextSubwordEnd,
12661        window: &mut Window,
12662        cx: &mut Context<Self>,
12663    ) {
12664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12665        self.change_selections(Default::default(), window, cx, |s| {
12666            s.move_cursors_with(|map, head, _| {
12667                (movement::next_subword_end(map, head), SelectionGoal::None)
12668            });
12669        })
12670    }
12671
12672    pub fn select_to_next_word_end(
12673        &mut self,
12674        _: &SelectToNextWordEnd,
12675        window: &mut Window,
12676        cx: &mut Context<Self>,
12677    ) {
12678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12679        self.change_selections(Default::default(), window, cx, |s| {
12680            s.move_heads_with(|map, head, _| {
12681                (movement::next_word_end(map, head), SelectionGoal::None)
12682            });
12683        })
12684    }
12685
12686    pub fn select_to_next_subword_end(
12687        &mut self,
12688        _: &SelectToNextSubwordEnd,
12689        window: &mut Window,
12690        cx: &mut Context<Self>,
12691    ) {
12692        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12693        self.change_selections(Default::default(), window, cx, |s| {
12694            s.move_heads_with(|map, head, _| {
12695                (movement::next_subword_end(map, head), SelectionGoal::None)
12696            });
12697        })
12698    }
12699
12700    pub fn delete_to_next_word_end(
12701        &mut self,
12702        action: &DeleteToNextWordEnd,
12703        window: &mut Window,
12704        cx: &mut Context<Self>,
12705    ) {
12706        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12707        self.transact(window, cx, |this, window, cx| {
12708            this.change_selections(Default::default(), window, cx, |s| {
12709                s.move_with(|map, selection| {
12710                    if selection.is_empty() {
12711                        let cursor = if action.ignore_newlines {
12712                            movement::next_word_end(map, selection.head())
12713                        } else {
12714                            movement::next_word_end_or_newline(map, selection.head())
12715                        };
12716                        selection.set_head(cursor, SelectionGoal::None);
12717                    }
12718                });
12719            });
12720            this.insert("", window, cx);
12721        });
12722    }
12723
12724    pub fn delete_to_next_subword_end(
12725        &mut self,
12726        _: &DeleteToNextSubwordEnd,
12727        window: &mut Window,
12728        cx: &mut Context<Self>,
12729    ) {
12730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12731        self.transact(window, cx, |this, window, cx| {
12732            this.change_selections(Default::default(), window, cx, |s| {
12733                s.move_with(|map, selection| {
12734                    if selection.is_empty() {
12735                        let cursor = movement::next_subword_end(map, selection.head());
12736                        selection.set_head(cursor, SelectionGoal::None);
12737                    }
12738                });
12739            });
12740            this.insert("", window, cx);
12741        });
12742    }
12743
12744    pub fn move_to_beginning_of_line(
12745        &mut self,
12746        action: &MoveToBeginningOfLine,
12747        window: &mut Window,
12748        cx: &mut Context<Self>,
12749    ) {
12750        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12751        self.change_selections(Default::default(), window, cx, |s| {
12752            s.move_cursors_with(|map, head, _| {
12753                (
12754                    movement::indented_line_beginning(
12755                        map,
12756                        head,
12757                        action.stop_at_soft_wraps,
12758                        action.stop_at_indent,
12759                    ),
12760                    SelectionGoal::None,
12761                )
12762            });
12763        })
12764    }
12765
12766    pub fn select_to_beginning_of_line(
12767        &mut self,
12768        action: &SelectToBeginningOfLine,
12769        window: &mut Window,
12770        cx: &mut Context<Self>,
12771    ) {
12772        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12773        self.change_selections(Default::default(), window, cx, |s| {
12774            s.move_heads_with(|map, head, _| {
12775                (
12776                    movement::indented_line_beginning(
12777                        map,
12778                        head,
12779                        action.stop_at_soft_wraps,
12780                        action.stop_at_indent,
12781                    ),
12782                    SelectionGoal::None,
12783                )
12784            });
12785        });
12786    }
12787
12788    pub fn delete_to_beginning_of_line(
12789        &mut self,
12790        action: &DeleteToBeginningOfLine,
12791        window: &mut Window,
12792        cx: &mut Context<Self>,
12793    ) {
12794        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12795        self.transact(window, cx, |this, window, cx| {
12796            this.change_selections(Default::default(), window, cx, |s| {
12797                s.move_with(|_, selection| {
12798                    selection.reversed = true;
12799                });
12800            });
12801
12802            this.select_to_beginning_of_line(
12803                &SelectToBeginningOfLine {
12804                    stop_at_soft_wraps: false,
12805                    stop_at_indent: action.stop_at_indent,
12806                },
12807                window,
12808                cx,
12809            );
12810            this.backspace(&Backspace, window, cx);
12811        });
12812    }
12813
12814    pub fn move_to_end_of_line(
12815        &mut self,
12816        action: &MoveToEndOfLine,
12817        window: &mut Window,
12818        cx: &mut Context<Self>,
12819    ) {
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12821        self.change_selections(Default::default(), window, cx, |s| {
12822            s.move_cursors_with(|map, head, _| {
12823                (
12824                    movement::line_end(map, head, action.stop_at_soft_wraps),
12825                    SelectionGoal::None,
12826                )
12827            });
12828        })
12829    }
12830
12831    pub fn select_to_end_of_line(
12832        &mut self,
12833        action: &SelectToEndOfLine,
12834        window: &mut Window,
12835        cx: &mut Context<Self>,
12836    ) {
12837        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12838        self.change_selections(Default::default(), window, cx, |s| {
12839            s.move_heads_with(|map, head, _| {
12840                (
12841                    movement::line_end(map, head, action.stop_at_soft_wraps),
12842                    SelectionGoal::None,
12843                )
12844            });
12845        })
12846    }
12847
12848    pub fn delete_to_end_of_line(
12849        &mut self,
12850        _: &DeleteToEndOfLine,
12851        window: &mut Window,
12852        cx: &mut Context<Self>,
12853    ) {
12854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12855        self.transact(window, cx, |this, window, cx| {
12856            this.select_to_end_of_line(
12857                &SelectToEndOfLine {
12858                    stop_at_soft_wraps: false,
12859                },
12860                window,
12861                cx,
12862            );
12863            this.delete(&Delete, window, cx);
12864        });
12865    }
12866
12867    pub fn cut_to_end_of_line(
12868        &mut self,
12869        _: &CutToEndOfLine,
12870        window: &mut Window,
12871        cx: &mut Context<Self>,
12872    ) {
12873        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12874        self.transact(window, cx, |this, window, cx| {
12875            this.select_to_end_of_line(
12876                &SelectToEndOfLine {
12877                    stop_at_soft_wraps: false,
12878                },
12879                window,
12880                cx,
12881            );
12882            this.cut(&Cut, window, cx);
12883        });
12884    }
12885
12886    pub fn move_to_start_of_paragraph(
12887        &mut self,
12888        _: &MoveToStartOfParagraph,
12889        window: &mut Window,
12890        cx: &mut Context<Self>,
12891    ) {
12892        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12893            cx.propagate();
12894            return;
12895        }
12896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12897        self.change_selections(Default::default(), window, cx, |s| {
12898            s.move_with(|map, selection| {
12899                selection.collapse_to(
12900                    movement::start_of_paragraph(map, selection.head(), 1),
12901                    SelectionGoal::None,
12902                )
12903            });
12904        })
12905    }
12906
12907    pub fn move_to_end_of_paragraph(
12908        &mut self,
12909        _: &MoveToEndOfParagraph,
12910        window: &mut Window,
12911        cx: &mut Context<Self>,
12912    ) {
12913        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12914            cx.propagate();
12915            return;
12916        }
12917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12918        self.change_selections(Default::default(), window, cx, |s| {
12919            s.move_with(|map, selection| {
12920                selection.collapse_to(
12921                    movement::end_of_paragraph(map, selection.head(), 1),
12922                    SelectionGoal::None,
12923                )
12924            });
12925        })
12926    }
12927
12928    pub fn select_to_start_of_paragraph(
12929        &mut self,
12930        _: &SelectToStartOfParagraph,
12931        window: &mut Window,
12932        cx: &mut Context<Self>,
12933    ) {
12934        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12935            cx.propagate();
12936            return;
12937        }
12938        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12939        self.change_selections(Default::default(), window, cx, |s| {
12940            s.move_heads_with(|map, head, _| {
12941                (
12942                    movement::start_of_paragraph(map, head, 1),
12943                    SelectionGoal::None,
12944                )
12945            });
12946        })
12947    }
12948
12949    pub fn select_to_end_of_paragraph(
12950        &mut self,
12951        _: &SelectToEndOfParagraph,
12952        window: &mut Window,
12953        cx: &mut Context<Self>,
12954    ) {
12955        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12956            cx.propagate();
12957            return;
12958        }
12959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12960        self.change_selections(Default::default(), window, cx, |s| {
12961            s.move_heads_with(|map, head, _| {
12962                (
12963                    movement::end_of_paragraph(map, head, 1),
12964                    SelectionGoal::None,
12965                )
12966            });
12967        })
12968    }
12969
12970    pub fn move_to_start_of_excerpt(
12971        &mut self,
12972        _: &MoveToStartOfExcerpt,
12973        window: &mut Window,
12974        cx: &mut Context<Self>,
12975    ) {
12976        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12977            cx.propagate();
12978            return;
12979        }
12980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12981        self.change_selections(Default::default(), window, cx, |s| {
12982            s.move_with(|map, selection| {
12983                selection.collapse_to(
12984                    movement::start_of_excerpt(
12985                        map,
12986                        selection.head(),
12987                        workspace::searchable::Direction::Prev,
12988                    ),
12989                    SelectionGoal::None,
12990                )
12991            });
12992        })
12993    }
12994
12995    pub fn move_to_start_of_next_excerpt(
12996        &mut self,
12997        _: &MoveToStartOfNextExcerpt,
12998        window: &mut Window,
12999        cx: &mut Context<Self>,
13000    ) {
13001        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13002            cx.propagate();
13003            return;
13004        }
13005
13006        self.change_selections(Default::default(), window, cx, |s| {
13007            s.move_with(|map, selection| {
13008                selection.collapse_to(
13009                    movement::start_of_excerpt(
13010                        map,
13011                        selection.head(),
13012                        workspace::searchable::Direction::Next,
13013                    ),
13014                    SelectionGoal::None,
13015                )
13016            });
13017        })
13018    }
13019
13020    pub fn move_to_end_of_excerpt(
13021        &mut self,
13022        _: &MoveToEndOfExcerpt,
13023        window: &mut Window,
13024        cx: &mut Context<Self>,
13025    ) {
13026        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13027            cx.propagate();
13028            return;
13029        }
13030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13031        self.change_selections(Default::default(), window, cx, |s| {
13032            s.move_with(|map, selection| {
13033                selection.collapse_to(
13034                    movement::end_of_excerpt(
13035                        map,
13036                        selection.head(),
13037                        workspace::searchable::Direction::Next,
13038                    ),
13039                    SelectionGoal::None,
13040                )
13041            });
13042        })
13043    }
13044
13045    pub fn move_to_end_of_previous_excerpt(
13046        &mut self,
13047        _: &MoveToEndOfPreviousExcerpt,
13048        window: &mut Window,
13049        cx: &mut Context<Self>,
13050    ) {
13051        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13052            cx.propagate();
13053            return;
13054        }
13055        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13056        self.change_selections(Default::default(), window, cx, |s| {
13057            s.move_with(|map, selection| {
13058                selection.collapse_to(
13059                    movement::end_of_excerpt(
13060                        map,
13061                        selection.head(),
13062                        workspace::searchable::Direction::Prev,
13063                    ),
13064                    SelectionGoal::None,
13065                )
13066            });
13067        })
13068    }
13069
13070    pub fn select_to_start_of_excerpt(
13071        &mut self,
13072        _: &SelectToStartOfExcerpt,
13073        window: &mut Window,
13074        cx: &mut Context<Self>,
13075    ) {
13076        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13077            cx.propagate();
13078            return;
13079        }
13080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13081        self.change_selections(Default::default(), window, cx, |s| {
13082            s.move_heads_with(|map, head, _| {
13083                (
13084                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13085                    SelectionGoal::None,
13086                )
13087            });
13088        })
13089    }
13090
13091    pub fn select_to_start_of_next_excerpt(
13092        &mut self,
13093        _: &SelectToStartOfNextExcerpt,
13094        window: &mut Window,
13095        cx: &mut Context<Self>,
13096    ) {
13097        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13098            cx.propagate();
13099            return;
13100        }
13101        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13102        self.change_selections(Default::default(), window, cx, |s| {
13103            s.move_heads_with(|map, head, _| {
13104                (
13105                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13106                    SelectionGoal::None,
13107                )
13108            });
13109        })
13110    }
13111
13112    pub fn select_to_end_of_excerpt(
13113        &mut self,
13114        _: &SelectToEndOfExcerpt,
13115        window: &mut Window,
13116        cx: &mut Context<Self>,
13117    ) {
13118        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13119            cx.propagate();
13120            return;
13121        }
13122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13123        self.change_selections(Default::default(), window, cx, |s| {
13124            s.move_heads_with(|map, head, _| {
13125                (
13126                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13127                    SelectionGoal::None,
13128                )
13129            });
13130        })
13131    }
13132
13133    pub fn select_to_end_of_previous_excerpt(
13134        &mut self,
13135        _: &SelectToEndOfPreviousExcerpt,
13136        window: &mut Window,
13137        cx: &mut Context<Self>,
13138    ) {
13139        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13140            cx.propagate();
13141            return;
13142        }
13143        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13144        self.change_selections(Default::default(), window, cx, |s| {
13145            s.move_heads_with(|map, head, _| {
13146                (
13147                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13148                    SelectionGoal::None,
13149                )
13150            });
13151        })
13152    }
13153
13154    pub fn move_to_beginning(
13155        &mut self,
13156        _: &MoveToBeginning,
13157        window: &mut Window,
13158        cx: &mut Context<Self>,
13159    ) {
13160        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13161            cx.propagate();
13162            return;
13163        }
13164        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13165        self.change_selections(Default::default(), window, cx, |s| {
13166            s.select_ranges(vec![0..0]);
13167        });
13168    }
13169
13170    pub fn select_to_beginning(
13171        &mut self,
13172        _: &SelectToBeginning,
13173        window: &mut Window,
13174        cx: &mut Context<Self>,
13175    ) {
13176        let mut selection = self.selections.last::<Point>(cx);
13177        selection.set_head(Point::zero(), SelectionGoal::None);
13178        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13179        self.change_selections(Default::default(), window, cx, |s| {
13180            s.select(vec![selection]);
13181        });
13182    }
13183
13184    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13185        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13186            cx.propagate();
13187            return;
13188        }
13189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13190        let cursor = self.buffer.read(cx).read(cx).len();
13191        self.change_selections(Default::default(), window, cx, |s| {
13192            s.select_ranges(vec![cursor..cursor])
13193        });
13194    }
13195
13196    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13197        self.nav_history = nav_history;
13198    }
13199
13200    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13201        self.nav_history.as_ref()
13202    }
13203
13204    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13205        self.push_to_nav_history(
13206            self.selections.newest_anchor().head(),
13207            None,
13208            false,
13209            true,
13210            cx,
13211        );
13212    }
13213
13214    fn push_to_nav_history(
13215        &mut self,
13216        cursor_anchor: Anchor,
13217        new_position: Option<Point>,
13218        is_deactivate: bool,
13219        always: bool,
13220        cx: &mut Context<Self>,
13221    ) {
13222        if let Some(nav_history) = self.nav_history.as_mut() {
13223            let buffer = self.buffer.read(cx).read(cx);
13224            let cursor_position = cursor_anchor.to_point(&buffer);
13225            let scroll_state = self.scroll_manager.anchor();
13226            let scroll_top_row = scroll_state.top_row(&buffer);
13227            drop(buffer);
13228
13229            if let Some(new_position) = new_position {
13230                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13231                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13232                    return;
13233                }
13234            }
13235
13236            nav_history.push(
13237                Some(NavigationData {
13238                    cursor_anchor,
13239                    cursor_position,
13240                    scroll_anchor: scroll_state,
13241                    scroll_top_row,
13242                }),
13243                cx,
13244            );
13245            cx.emit(EditorEvent::PushedToNavHistory {
13246                anchor: cursor_anchor,
13247                is_deactivate,
13248            })
13249        }
13250    }
13251
13252    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13253        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13254        let buffer = self.buffer.read(cx).snapshot(cx);
13255        let mut selection = self.selections.first::<usize>(cx);
13256        selection.set_head(buffer.len(), SelectionGoal::None);
13257        self.change_selections(Default::default(), window, cx, |s| {
13258            s.select(vec![selection]);
13259        });
13260    }
13261
13262    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13264        let end = self.buffer.read(cx).read(cx).len();
13265        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13266            s.select_ranges(vec![0..end]);
13267        });
13268    }
13269
13270    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13271        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13272        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13273        let mut selections = self.selections.all::<Point>(cx);
13274        let max_point = display_map.buffer_snapshot.max_point();
13275        for selection in &mut selections {
13276            let rows = selection.spanned_rows(true, &display_map);
13277            selection.start = Point::new(rows.start.0, 0);
13278            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13279            selection.reversed = false;
13280        }
13281        self.change_selections(Default::default(), window, cx, |s| {
13282            s.select(selections);
13283        });
13284    }
13285
13286    pub fn split_selection_into_lines(
13287        &mut self,
13288        _: &SplitSelectionIntoLines,
13289        window: &mut Window,
13290        cx: &mut Context<Self>,
13291    ) {
13292        let selections = self
13293            .selections
13294            .all::<Point>(cx)
13295            .into_iter()
13296            .map(|selection| selection.start..selection.end)
13297            .collect::<Vec<_>>();
13298        self.unfold_ranges(&selections, true, true, cx);
13299
13300        let mut new_selection_ranges = Vec::new();
13301        {
13302            let buffer = self.buffer.read(cx).read(cx);
13303            for selection in selections {
13304                for row in selection.start.row..selection.end.row {
13305                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13306                    new_selection_ranges.push(cursor..cursor);
13307                }
13308
13309                let is_multiline_selection = selection.start.row != selection.end.row;
13310                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13311                // so this action feels more ergonomic when paired with other selection operations
13312                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13313                if !should_skip_last {
13314                    new_selection_ranges.push(selection.end..selection.end);
13315                }
13316            }
13317        }
13318        self.change_selections(Default::default(), window, cx, |s| {
13319            s.select_ranges(new_selection_ranges);
13320        });
13321    }
13322
13323    pub fn add_selection_above(
13324        &mut self,
13325        _: &AddSelectionAbove,
13326        window: &mut Window,
13327        cx: &mut Context<Self>,
13328    ) {
13329        self.add_selection(true, window, cx);
13330    }
13331
13332    pub fn add_selection_below(
13333        &mut self,
13334        _: &AddSelectionBelow,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        self.add_selection(false, window, cx);
13339    }
13340
13341    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13342        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13343
13344        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13345        let all_selections = self.selections.all::<Point>(cx);
13346        let text_layout_details = self.text_layout_details(window);
13347
13348        let (mut columnar_selections, new_selections_to_columnarize) = {
13349            if let Some(state) = self.add_selections_state.as_ref() {
13350                let columnar_selection_ids: HashSet<_> = state
13351                    .groups
13352                    .iter()
13353                    .flat_map(|group| group.stack.iter())
13354                    .copied()
13355                    .collect();
13356
13357                all_selections
13358                    .into_iter()
13359                    .partition(|s| columnar_selection_ids.contains(&s.id))
13360            } else {
13361                (Vec::new(), all_selections)
13362            }
13363        };
13364
13365        let mut state = self
13366            .add_selections_state
13367            .take()
13368            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13369
13370        for selection in new_selections_to_columnarize {
13371            let range = selection.display_range(&display_map).sorted();
13372            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13373            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13374            let positions = start_x.min(end_x)..start_x.max(end_x);
13375            let mut stack = Vec::new();
13376            for row in range.start.row().0..=range.end.row().0 {
13377                if let Some(selection) = self.selections.build_columnar_selection(
13378                    &display_map,
13379                    DisplayRow(row),
13380                    &positions,
13381                    selection.reversed,
13382                    &text_layout_details,
13383                ) {
13384                    stack.push(selection.id);
13385                    columnar_selections.push(selection);
13386                }
13387            }
13388            if !stack.is_empty() {
13389                if above {
13390                    stack.reverse();
13391                }
13392                state.groups.push(AddSelectionsGroup { above, stack });
13393            }
13394        }
13395
13396        let mut final_selections = Vec::new();
13397        let end_row = if above {
13398            DisplayRow(0)
13399        } else {
13400            display_map.max_point().row()
13401        };
13402
13403        let mut last_added_item_per_group = HashMap::default();
13404        for group in state.groups.iter_mut() {
13405            if let Some(last_id) = group.stack.last() {
13406                last_added_item_per_group.insert(*last_id, group);
13407            }
13408        }
13409
13410        for selection in columnar_selections {
13411            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13412                if above == group.above {
13413                    let range = selection.display_range(&display_map).sorted();
13414                    debug_assert_eq!(range.start.row(), range.end.row());
13415                    let mut row = range.start.row();
13416                    let positions =
13417                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13418                            px(start)..px(end)
13419                        } else {
13420                            let start_x =
13421                                display_map.x_for_display_point(range.start, &text_layout_details);
13422                            let end_x =
13423                                display_map.x_for_display_point(range.end, &text_layout_details);
13424                            start_x.min(end_x)..start_x.max(end_x)
13425                        };
13426
13427                    let mut maybe_new_selection = None;
13428                    while row != end_row {
13429                        if above {
13430                            row.0 -= 1;
13431                        } else {
13432                            row.0 += 1;
13433                        }
13434                        if let Some(new_selection) = self.selections.build_columnar_selection(
13435                            &display_map,
13436                            row,
13437                            &positions,
13438                            selection.reversed,
13439                            &text_layout_details,
13440                        ) {
13441                            maybe_new_selection = Some(new_selection);
13442                            break;
13443                        }
13444                    }
13445
13446                    if let Some(new_selection) = maybe_new_selection {
13447                        group.stack.push(new_selection.id);
13448                        if above {
13449                            final_selections.push(new_selection);
13450                            final_selections.push(selection);
13451                        } else {
13452                            final_selections.push(selection);
13453                            final_selections.push(new_selection);
13454                        }
13455                    } else {
13456                        final_selections.push(selection);
13457                    }
13458                } else {
13459                    group.stack.pop();
13460                }
13461            } else {
13462                final_selections.push(selection);
13463            }
13464        }
13465
13466        self.change_selections(Default::default(), window, cx, |s| {
13467            s.select(final_selections);
13468        });
13469
13470        let final_selection_ids: HashSet<_> = self
13471            .selections
13472            .all::<Point>(cx)
13473            .iter()
13474            .map(|s| s.id)
13475            .collect();
13476        state.groups.retain_mut(|group| {
13477            // selections might get merged above so we remove invalid items from stacks
13478            group.stack.retain(|id| final_selection_ids.contains(id));
13479
13480            // single selection in stack can be treated as initial state
13481            group.stack.len() > 1
13482        });
13483
13484        if !state.groups.is_empty() {
13485            self.add_selections_state = Some(state);
13486        }
13487    }
13488
13489    fn select_match_ranges(
13490        &mut self,
13491        range: Range<usize>,
13492        reversed: bool,
13493        replace_newest: bool,
13494        auto_scroll: Option<Autoscroll>,
13495        window: &mut Window,
13496        cx: &mut Context<Editor>,
13497    ) {
13498        self.unfold_ranges(
13499            std::slice::from_ref(&range),
13500            false,
13501            auto_scroll.is_some(),
13502            cx,
13503        );
13504        let effects = if let Some(scroll) = auto_scroll {
13505            SelectionEffects::scroll(scroll)
13506        } else {
13507            SelectionEffects::no_scroll()
13508        };
13509        self.change_selections(effects, window, cx, |s| {
13510            if replace_newest {
13511                s.delete(s.newest_anchor().id);
13512            }
13513            if reversed {
13514                s.insert_range(range.end..range.start);
13515            } else {
13516                s.insert_range(range);
13517            }
13518        });
13519    }
13520
13521    pub fn select_next_match_internal(
13522        &mut self,
13523        display_map: &DisplaySnapshot,
13524        replace_newest: bool,
13525        autoscroll: Option<Autoscroll>,
13526        window: &mut Window,
13527        cx: &mut Context<Self>,
13528    ) -> Result<()> {
13529        let buffer = &display_map.buffer_snapshot;
13530        let mut selections = self.selections.all::<usize>(cx);
13531        if let Some(mut select_next_state) = self.select_next_state.take() {
13532            let query = &select_next_state.query;
13533            if !select_next_state.done {
13534                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13535                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13536                let mut next_selected_range = None;
13537
13538                let bytes_after_last_selection =
13539                    buffer.bytes_in_range(last_selection.end..buffer.len());
13540                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13541                let query_matches = query
13542                    .stream_find_iter(bytes_after_last_selection)
13543                    .map(|result| (last_selection.end, result))
13544                    .chain(
13545                        query
13546                            .stream_find_iter(bytes_before_first_selection)
13547                            .map(|result| (0, result)),
13548                    );
13549
13550                for (start_offset, query_match) in query_matches {
13551                    let query_match = query_match.unwrap(); // can only fail due to I/O
13552                    let offset_range =
13553                        start_offset + query_match.start()..start_offset + query_match.end();
13554
13555                    if !select_next_state.wordwise
13556                        || (!buffer.is_inside_word(offset_range.start, false)
13557                            && !buffer.is_inside_word(offset_range.end, false))
13558                    {
13559                        // TODO: This is n^2, because we might check all the selections
13560                        if !selections
13561                            .iter()
13562                            .any(|selection| selection.range().overlaps(&offset_range))
13563                        {
13564                            next_selected_range = Some(offset_range);
13565                            break;
13566                        }
13567                    }
13568                }
13569
13570                if let Some(next_selected_range) = next_selected_range {
13571                    self.select_match_ranges(
13572                        next_selected_range,
13573                        last_selection.reversed,
13574                        replace_newest,
13575                        autoscroll,
13576                        window,
13577                        cx,
13578                    );
13579                } else {
13580                    select_next_state.done = true;
13581                }
13582            }
13583
13584            self.select_next_state = Some(select_next_state);
13585        } else {
13586            let mut only_carets = true;
13587            let mut same_text_selected = true;
13588            let mut selected_text = None;
13589
13590            let mut selections_iter = selections.iter().peekable();
13591            while let Some(selection) = selections_iter.next() {
13592                if selection.start != selection.end {
13593                    only_carets = false;
13594                }
13595
13596                if same_text_selected {
13597                    if selected_text.is_none() {
13598                        selected_text =
13599                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13600                    }
13601
13602                    if let Some(next_selection) = selections_iter.peek() {
13603                        if next_selection.range().len() == selection.range().len() {
13604                            let next_selected_text = buffer
13605                                .text_for_range(next_selection.range())
13606                                .collect::<String>();
13607                            if Some(next_selected_text) != selected_text {
13608                                same_text_selected = false;
13609                                selected_text = None;
13610                            }
13611                        } else {
13612                            same_text_selected = false;
13613                            selected_text = None;
13614                        }
13615                    }
13616                }
13617            }
13618
13619            if only_carets {
13620                for selection in &mut selections {
13621                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13622                    selection.start = word_range.start;
13623                    selection.end = word_range.end;
13624                    selection.goal = SelectionGoal::None;
13625                    selection.reversed = false;
13626                    self.select_match_ranges(
13627                        selection.start..selection.end,
13628                        selection.reversed,
13629                        replace_newest,
13630                        autoscroll,
13631                        window,
13632                        cx,
13633                    );
13634                }
13635
13636                if selections.len() == 1 {
13637                    let selection = selections
13638                        .last()
13639                        .expect("ensured that there's only one selection");
13640                    let query = buffer
13641                        .text_for_range(selection.start..selection.end)
13642                        .collect::<String>();
13643                    let is_empty = query.is_empty();
13644                    let select_state = SelectNextState {
13645                        query: AhoCorasick::new(&[query])?,
13646                        wordwise: true,
13647                        done: is_empty,
13648                    };
13649                    self.select_next_state = Some(select_state);
13650                } else {
13651                    self.select_next_state = None;
13652                }
13653            } else if let Some(selected_text) = selected_text {
13654                self.select_next_state = Some(SelectNextState {
13655                    query: AhoCorasick::new(&[selected_text])?,
13656                    wordwise: false,
13657                    done: false,
13658                });
13659                self.select_next_match_internal(
13660                    display_map,
13661                    replace_newest,
13662                    autoscroll,
13663                    window,
13664                    cx,
13665                )?;
13666            }
13667        }
13668        Ok(())
13669    }
13670
13671    pub fn select_all_matches(
13672        &mut self,
13673        _action: &SelectAllMatches,
13674        window: &mut Window,
13675        cx: &mut Context<Self>,
13676    ) -> Result<()> {
13677        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13678
13679        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13680
13681        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13682        let Some(select_next_state) = self.select_next_state.as_mut() else {
13683            return Ok(());
13684        };
13685        if select_next_state.done {
13686            return Ok(());
13687        }
13688
13689        let mut new_selections = Vec::new();
13690
13691        let reversed = self.selections.oldest::<usize>(cx).reversed;
13692        let buffer = &display_map.buffer_snapshot;
13693        let query_matches = select_next_state
13694            .query
13695            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13696
13697        for query_match in query_matches.into_iter() {
13698            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13699            let offset_range = if reversed {
13700                query_match.end()..query_match.start()
13701            } else {
13702                query_match.start()..query_match.end()
13703            };
13704
13705            if !select_next_state.wordwise
13706                || (!buffer.is_inside_word(offset_range.start, false)
13707                    && !buffer.is_inside_word(offset_range.end, false))
13708            {
13709                new_selections.push(offset_range.start..offset_range.end);
13710            }
13711        }
13712
13713        select_next_state.done = true;
13714
13715        if new_selections.is_empty() {
13716            log::error!("bug: new_selections is empty in select_all_matches");
13717            return Ok(());
13718        }
13719
13720        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13721        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13722            selections.select_ranges(new_selections)
13723        });
13724
13725        Ok(())
13726    }
13727
13728    pub fn select_next(
13729        &mut self,
13730        action: &SelectNext,
13731        window: &mut Window,
13732        cx: &mut Context<Self>,
13733    ) -> Result<()> {
13734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13735        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13736        self.select_next_match_internal(
13737            &display_map,
13738            action.replace_newest,
13739            Some(Autoscroll::newest()),
13740            window,
13741            cx,
13742        )?;
13743        Ok(())
13744    }
13745
13746    pub fn select_previous(
13747        &mut self,
13748        action: &SelectPrevious,
13749        window: &mut Window,
13750        cx: &mut Context<Self>,
13751    ) -> Result<()> {
13752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13753        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13754        let buffer = &display_map.buffer_snapshot;
13755        let mut selections = self.selections.all::<usize>(cx);
13756        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13757            let query = &select_prev_state.query;
13758            if !select_prev_state.done {
13759                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13760                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13761                let mut next_selected_range = None;
13762                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13763                let bytes_before_last_selection =
13764                    buffer.reversed_bytes_in_range(0..last_selection.start);
13765                let bytes_after_first_selection =
13766                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13767                let query_matches = query
13768                    .stream_find_iter(bytes_before_last_selection)
13769                    .map(|result| (last_selection.start, result))
13770                    .chain(
13771                        query
13772                            .stream_find_iter(bytes_after_first_selection)
13773                            .map(|result| (buffer.len(), result)),
13774                    );
13775                for (end_offset, query_match) in query_matches {
13776                    let query_match = query_match.unwrap(); // can only fail due to I/O
13777                    let offset_range =
13778                        end_offset - query_match.end()..end_offset - query_match.start();
13779
13780                    if !select_prev_state.wordwise
13781                        || (!buffer.is_inside_word(offset_range.start, false)
13782                            && !buffer.is_inside_word(offset_range.end, false))
13783                    {
13784                        next_selected_range = Some(offset_range);
13785                        break;
13786                    }
13787                }
13788
13789                if let Some(next_selected_range) = next_selected_range {
13790                    self.select_match_ranges(
13791                        next_selected_range,
13792                        last_selection.reversed,
13793                        action.replace_newest,
13794                        Some(Autoscroll::newest()),
13795                        window,
13796                        cx,
13797                    );
13798                } else {
13799                    select_prev_state.done = true;
13800                }
13801            }
13802
13803            self.select_prev_state = Some(select_prev_state);
13804        } else {
13805            let mut only_carets = true;
13806            let mut same_text_selected = true;
13807            let mut selected_text = None;
13808
13809            let mut selections_iter = selections.iter().peekable();
13810            while let Some(selection) = selections_iter.next() {
13811                if selection.start != selection.end {
13812                    only_carets = false;
13813                }
13814
13815                if same_text_selected {
13816                    if selected_text.is_none() {
13817                        selected_text =
13818                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13819                    }
13820
13821                    if let Some(next_selection) = selections_iter.peek() {
13822                        if next_selection.range().len() == selection.range().len() {
13823                            let next_selected_text = buffer
13824                                .text_for_range(next_selection.range())
13825                                .collect::<String>();
13826                            if Some(next_selected_text) != selected_text {
13827                                same_text_selected = false;
13828                                selected_text = None;
13829                            }
13830                        } else {
13831                            same_text_selected = false;
13832                            selected_text = None;
13833                        }
13834                    }
13835                }
13836            }
13837
13838            if only_carets {
13839                for selection in &mut selections {
13840                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13841                    selection.start = word_range.start;
13842                    selection.end = word_range.end;
13843                    selection.goal = SelectionGoal::None;
13844                    selection.reversed = false;
13845                    self.select_match_ranges(
13846                        selection.start..selection.end,
13847                        selection.reversed,
13848                        action.replace_newest,
13849                        Some(Autoscroll::newest()),
13850                        window,
13851                        cx,
13852                    );
13853                }
13854                if selections.len() == 1 {
13855                    let selection = selections
13856                        .last()
13857                        .expect("ensured that there's only one selection");
13858                    let query = buffer
13859                        .text_for_range(selection.start..selection.end)
13860                        .collect::<String>();
13861                    let is_empty = query.is_empty();
13862                    let select_state = SelectNextState {
13863                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13864                        wordwise: true,
13865                        done: is_empty,
13866                    };
13867                    self.select_prev_state = Some(select_state);
13868                } else {
13869                    self.select_prev_state = None;
13870                }
13871            } else if let Some(selected_text) = selected_text {
13872                self.select_prev_state = Some(SelectNextState {
13873                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13874                    wordwise: false,
13875                    done: false,
13876                });
13877                self.select_previous(action, window, cx)?;
13878            }
13879        }
13880        Ok(())
13881    }
13882
13883    pub fn find_next_match(
13884        &mut self,
13885        _: &FindNextMatch,
13886        window: &mut Window,
13887        cx: &mut Context<Self>,
13888    ) -> Result<()> {
13889        let selections = self.selections.disjoint_anchors();
13890        match selections.first() {
13891            Some(first) if selections.len() >= 2 => {
13892                self.change_selections(Default::default(), window, cx, |s| {
13893                    s.select_ranges([first.range()]);
13894                });
13895            }
13896            _ => self.select_next(
13897                &SelectNext {
13898                    replace_newest: true,
13899                },
13900                window,
13901                cx,
13902            )?,
13903        }
13904        Ok(())
13905    }
13906
13907    pub fn find_previous_match(
13908        &mut self,
13909        _: &FindPreviousMatch,
13910        window: &mut Window,
13911        cx: &mut Context<Self>,
13912    ) -> Result<()> {
13913        let selections = self.selections.disjoint_anchors();
13914        match selections.last() {
13915            Some(last) if selections.len() >= 2 => {
13916                self.change_selections(Default::default(), window, cx, |s| {
13917                    s.select_ranges([last.range()]);
13918                });
13919            }
13920            _ => self.select_previous(
13921                &SelectPrevious {
13922                    replace_newest: true,
13923                },
13924                window,
13925                cx,
13926            )?,
13927        }
13928        Ok(())
13929    }
13930
13931    pub fn toggle_comments(
13932        &mut self,
13933        action: &ToggleComments,
13934        window: &mut Window,
13935        cx: &mut Context<Self>,
13936    ) {
13937        if self.read_only(cx) {
13938            return;
13939        }
13940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13941        let text_layout_details = &self.text_layout_details(window);
13942        self.transact(window, cx, |this, window, cx| {
13943            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13944            let mut edits = Vec::new();
13945            let mut selection_edit_ranges = Vec::new();
13946            let mut last_toggled_row = None;
13947            let snapshot = this.buffer.read(cx).read(cx);
13948            let empty_str: Arc<str> = Arc::default();
13949            let mut suffixes_inserted = Vec::new();
13950            let ignore_indent = action.ignore_indent;
13951
13952            fn comment_prefix_range(
13953                snapshot: &MultiBufferSnapshot,
13954                row: MultiBufferRow,
13955                comment_prefix: &str,
13956                comment_prefix_whitespace: &str,
13957                ignore_indent: bool,
13958            ) -> Range<Point> {
13959                let indent_size = if ignore_indent {
13960                    0
13961                } else {
13962                    snapshot.indent_size_for_line(row).len
13963                };
13964
13965                let start = Point::new(row.0, indent_size);
13966
13967                let mut line_bytes = snapshot
13968                    .bytes_in_range(start..snapshot.max_point())
13969                    .flatten()
13970                    .copied();
13971
13972                // If this line currently begins with the line comment prefix, then record
13973                // the range containing the prefix.
13974                if line_bytes
13975                    .by_ref()
13976                    .take(comment_prefix.len())
13977                    .eq(comment_prefix.bytes())
13978                {
13979                    // Include any whitespace that matches the comment prefix.
13980                    let matching_whitespace_len = line_bytes
13981                        .zip(comment_prefix_whitespace.bytes())
13982                        .take_while(|(a, b)| a == b)
13983                        .count() as u32;
13984                    let end = Point::new(
13985                        start.row,
13986                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13987                    );
13988                    start..end
13989                } else {
13990                    start..start
13991                }
13992            }
13993
13994            fn comment_suffix_range(
13995                snapshot: &MultiBufferSnapshot,
13996                row: MultiBufferRow,
13997                comment_suffix: &str,
13998                comment_suffix_has_leading_space: bool,
13999            ) -> Range<Point> {
14000                let end = Point::new(row.0, snapshot.line_len(row));
14001                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14002
14003                let mut line_end_bytes = snapshot
14004                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14005                    .flatten()
14006                    .copied();
14007
14008                let leading_space_len = if suffix_start_column > 0
14009                    && line_end_bytes.next() == Some(b' ')
14010                    && comment_suffix_has_leading_space
14011                {
14012                    1
14013                } else {
14014                    0
14015                };
14016
14017                // If this line currently begins with the line comment prefix, then record
14018                // the range containing the prefix.
14019                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14020                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14021                    start..end
14022                } else {
14023                    end..end
14024                }
14025            }
14026
14027            // TODO: Handle selections that cross excerpts
14028            for selection in &mut selections {
14029                let start_column = snapshot
14030                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14031                    .len;
14032                let language = if let Some(language) =
14033                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14034                {
14035                    language
14036                } else {
14037                    continue;
14038                };
14039
14040                selection_edit_ranges.clear();
14041
14042                // If multiple selections contain a given row, avoid processing that
14043                // row more than once.
14044                let mut start_row = MultiBufferRow(selection.start.row);
14045                if last_toggled_row == Some(start_row) {
14046                    start_row = start_row.next_row();
14047                }
14048                let end_row =
14049                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14050                        MultiBufferRow(selection.end.row - 1)
14051                    } else {
14052                        MultiBufferRow(selection.end.row)
14053                    };
14054                last_toggled_row = Some(end_row);
14055
14056                if start_row > end_row {
14057                    continue;
14058                }
14059
14060                // If the language has line comments, toggle those.
14061                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14062
14063                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14064                if ignore_indent {
14065                    full_comment_prefixes = full_comment_prefixes
14066                        .into_iter()
14067                        .map(|s| Arc::from(s.trim_end()))
14068                        .collect();
14069                }
14070
14071                if !full_comment_prefixes.is_empty() {
14072                    let first_prefix = full_comment_prefixes
14073                        .first()
14074                        .expect("prefixes is non-empty");
14075                    let prefix_trimmed_lengths = full_comment_prefixes
14076                        .iter()
14077                        .map(|p| p.trim_end_matches(' ').len())
14078                        .collect::<SmallVec<[usize; 4]>>();
14079
14080                    let mut all_selection_lines_are_comments = true;
14081
14082                    for row in start_row.0..=end_row.0 {
14083                        let row = MultiBufferRow(row);
14084                        if start_row < end_row && snapshot.is_line_blank(row) {
14085                            continue;
14086                        }
14087
14088                        let prefix_range = full_comment_prefixes
14089                            .iter()
14090                            .zip(prefix_trimmed_lengths.iter().copied())
14091                            .map(|(prefix, trimmed_prefix_len)| {
14092                                comment_prefix_range(
14093                                    snapshot.deref(),
14094                                    row,
14095                                    &prefix[..trimmed_prefix_len],
14096                                    &prefix[trimmed_prefix_len..],
14097                                    ignore_indent,
14098                                )
14099                            })
14100                            .max_by_key(|range| range.end.column - range.start.column)
14101                            .expect("prefixes is non-empty");
14102
14103                        if prefix_range.is_empty() {
14104                            all_selection_lines_are_comments = false;
14105                        }
14106
14107                        selection_edit_ranges.push(prefix_range);
14108                    }
14109
14110                    if all_selection_lines_are_comments {
14111                        edits.extend(
14112                            selection_edit_ranges
14113                                .iter()
14114                                .cloned()
14115                                .map(|range| (range, empty_str.clone())),
14116                        );
14117                    } else {
14118                        let min_column = selection_edit_ranges
14119                            .iter()
14120                            .map(|range| range.start.column)
14121                            .min()
14122                            .unwrap_or(0);
14123                        edits.extend(selection_edit_ranges.iter().map(|range| {
14124                            let position = Point::new(range.start.row, min_column);
14125                            (position..position, first_prefix.clone())
14126                        }));
14127                    }
14128                } else if let Some((full_comment_prefix, comment_suffix)) =
14129                    language.block_comment_delimiters()
14130                {
14131                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14132                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14133                    let prefix_range = comment_prefix_range(
14134                        snapshot.deref(),
14135                        start_row,
14136                        comment_prefix,
14137                        comment_prefix_whitespace,
14138                        ignore_indent,
14139                    );
14140                    let suffix_range = comment_suffix_range(
14141                        snapshot.deref(),
14142                        end_row,
14143                        comment_suffix.trim_start_matches(' '),
14144                        comment_suffix.starts_with(' '),
14145                    );
14146
14147                    if prefix_range.is_empty() || suffix_range.is_empty() {
14148                        edits.push((
14149                            prefix_range.start..prefix_range.start,
14150                            full_comment_prefix.clone(),
14151                        ));
14152                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14153                        suffixes_inserted.push((end_row, comment_suffix.len()));
14154                    } else {
14155                        edits.push((prefix_range, empty_str.clone()));
14156                        edits.push((suffix_range, empty_str.clone()));
14157                    }
14158                } else {
14159                    continue;
14160                }
14161            }
14162
14163            drop(snapshot);
14164            this.buffer.update(cx, |buffer, cx| {
14165                buffer.edit(edits, None, cx);
14166            });
14167
14168            // Adjust selections so that they end before any comment suffixes that
14169            // were inserted.
14170            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14171            let mut selections = this.selections.all::<Point>(cx);
14172            let snapshot = this.buffer.read(cx).read(cx);
14173            for selection in &mut selections {
14174                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14175                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14176                        Ordering::Less => {
14177                            suffixes_inserted.next();
14178                            continue;
14179                        }
14180                        Ordering::Greater => break,
14181                        Ordering::Equal => {
14182                            if selection.end.column == snapshot.line_len(row) {
14183                                if selection.is_empty() {
14184                                    selection.start.column -= suffix_len as u32;
14185                                }
14186                                selection.end.column -= suffix_len as u32;
14187                            }
14188                            break;
14189                        }
14190                    }
14191                }
14192            }
14193
14194            drop(snapshot);
14195            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14196
14197            let selections = this.selections.all::<Point>(cx);
14198            let selections_on_single_row = selections.windows(2).all(|selections| {
14199                selections[0].start.row == selections[1].start.row
14200                    && selections[0].end.row == selections[1].end.row
14201                    && selections[0].start.row == selections[0].end.row
14202            });
14203            let selections_selecting = selections
14204                .iter()
14205                .any(|selection| selection.start != selection.end);
14206            let advance_downwards = action.advance_downwards
14207                && selections_on_single_row
14208                && !selections_selecting
14209                && !matches!(this.mode, EditorMode::SingleLine { .. });
14210
14211            if advance_downwards {
14212                let snapshot = this.buffer.read(cx).snapshot(cx);
14213
14214                this.change_selections(Default::default(), window, cx, |s| {
14215                    s.move_cursors_with(|display_snapshot, display_point, _| {
14216                        let mut point = display_point.to_point(display_snapshot);
14217                        point.row += 1;
14218                        point = snapshot.clip_point(point, Bias::Left);
14219                        let display_point = point.to_display_point(display_snapshot);
14220                        let goal = SelectionGoal::HorizontalPosition(
14221                            display_snapshot
14222                                .x_for_display_point(display_point, text_layout_details)
14223                                .into(),
14224                        );
14225                        (display_point, goal)
14226                    })
14227                });
14228            }
14229        });
14230    }
14231
14232    pub fn select_enclosing_symbol(
14233        &mut self,
14234        _: &SelectEnclosingSymbol,
14235        window: &mut Window,
14236        cx: &mut Context<Self>,
14237    ) {
14238        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14239
14240        let buffer = self.buffer.read(cx).snapshot(cx);
14241        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14242
14243        fn update_selection(
14244            selection: &Selection<usize>,
14245            buffer_snap: &MultiBufferSnapshot,
14246        ) -> Option<Selection<usize>> {
14247            let cursor = selection.head();
14248            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14249            for symbol in symbols.iter().rev() {
14250                let start = symbol.range.start.to_offset(buffer_snap);
14251                let end = symbol.range.end.to_offset(buffer_snap);
14252                let new_range = start..end;
14253                if start < selection.start || end > selection.end {
14254                    return Some(Selection {
14255                        id: selection.id,
14256                        start: new_range.start,
14257                        end: new_range.end,
14258                        goal: SelectionGoal::None,
14259                        reversed: selection.reversed,
14260                    });
14261                }
14262            }
14263            None
14264        }
14265
14266        let mut selected_larger_symbol = false;
14267        let new_selections = old_selections
14268            .iter()
14269            .map(|selection| match update_selection(selection, &buffer) {
14270                Some(new_selection) => {
14271                    if new_selection.range() != selection.range() {
14272                        selected_larger_symbol = true;
14273                    }
14274                    new_selection
14275                }
14276                None => selection.clone(),
14277            })
14278            .collect::<Vec<_>>();
14279
14280        if selected_larger_symbol {
14281            self.change_selections(Default::default(), window, cx, |s| {
14282                s.select(new_selections);
14283            });
14284        }
14285    }
14286
14287    pub fn select_larger_syntax_node(
14288        &mut self,
14289        _: &SelectLargerSyntaxNode,
14290        window: &mut Window,
14291        cx: &mut Context<Self>,
14292    ) {
14293        let Some(visible_row_count) = self.visible_row_count() else {
14294            return;
14295        };
14296        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14297        if old_selections.is_empty() {
14298            return;
14299        }
14300
14301        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14302
14303        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14304        let buffer = self.buffer.read(cx).snapshot(cx);
14305
14306        let mut selected_larger_node = false;
14307        let mut new_selections = old_selections
14308            .iter()
14309            .map(|selection| {
14310                let old_range = selection.start..selection.end;
14311
14312                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14313                    // manually select word at selection
14314                    if ["string_content", "inline"].contains(&node.kind()) {
14315                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14316                        // ignore if word is already selected
14317                        if !word_range.is_empty() && old_range != word_range {
14318                            let (last_word_range, _) =
14319                                buffer.surrounding_word(old_range.end, false);
14320                            // only select word if start and end point belongs to same word
14321                            if word_range == last_word_range {
14322                                selected_larger_node = true;
14323                                return Selection {
14324                                    id: selection.id,
14325                                    start: word_range.start,
14326                                    end: word_range.end,
14327                                    goal: SelectionGoal::None,
14328                                    reversed: selection.reversed,
14329                                };
14330                            }
14331                        }
14332                    }
14333                }
14334
14335                let mut new_range = old_range.clone();
14336                while let Some((_node, containing_range)) =
14337                    buffer.syntax_ancestor(new_range.clone())
14338                {
14339                    new_range = match containing_range {
14340                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14341                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14342                    };
14343                    if !display_map.intersects_fold(new_range.start)
14344                        && !display_map.intersects_fold(new_range.end)
14345                    {
14346                        break;
14347                    }
14348                }
14349
14350                selected_larger_node |= new_range != old_range;
14351                Selection {
14352                    id: selection.id,
14353                    start: new_range.start,
14354                    end: new_range.end,
14355                    goal: SelectionGoal::None,
14356                    reversed: selection.reversed,
14357                }
14358            })
14359            .collect::<Vec<_>>();
14360
14361        if !selected_larger_node {
14362            return; // don't put this call in the history
14363        }
14364
14365        // scroll based on transformation done to the last selection created by the user
14366        let (last_old, last_new) = old_selections
14367            .last()
14368            .zip(new_selections.last().cloned())
14369            .expect("old_selections isn't empty");
14370
14371        // revert selection
14372        let is_selection_reversed = {
14373            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14374            new_selections.last_mut().expect("checked above").reversed =
14375                should_newest_selection_be_reversed;
14376            should_newest_selection_be_reversed
14377        };
14378
14379        if selected_larger_node {
14380            self.select_syntax_node_history.disable_clearing = true;
14381            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14382                s.select(new_selections.clone());
14383            });
14384            self.select_syntax_node_history.disable_clearing = false;
14385        }
14386
14387        let start_row = last_new.start.to_display_point(&display_map).row().0;
14388        let end_row = last_new.end.to_display_point(&display_map).row().0;
14389        let selection_height = end_row - start_row + 1;
14390        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14391
14392        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14393        let scroll_behavior = if fits_on_the_screen {
14394            self.request_autoscroll(Autoscroll::fit(), cx);
14395            SelectSyntaxNodeScrollBehavior::FitSelection
14396        } else if is_selection_reversed {
14397            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14398            SelectSyntaxNodeScrollBehavior::CursorTop
14399        } else {
14400            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14401            SelectSyntaxNodeScrollBehavior::CursorBottom
14402        };
14403
14404        self.select_syntax_node_history.push((
14405            old_selections,
14406            scroll_behavior,
14407            is_selection_reversed,
14408        ));
14409    }
14410
14411    pub fn select_smaller_syntax_node(
14412        &mut self,
14413        _: &SelectSmallerSyntaxNode,
14414        window: &mut Window,
14415        cx: &mut Context<Self>,
14416    ) {
14417        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14418
14419        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14420            self.select_syntax_node_history.pop()
14421        {
14422            if let Some(selection) = selections.last_mut() {
14423                selection.reversed = is_selection_reversed;
14424            }
14425
14426            self.select_syntax_node_history.disable_clearing = true;
14427            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14428                s.select(selections.to_vec());
14429            });
14430            self.select_syntax_node_history.disable_clearing = false;
14431
14432            match scroll_behavior {
14433                SelectSyntaxNodeScrollBehavior::CursorTop => {
14434                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14435                }
14436                SelectSyntaxNodeScrollBehavior::FitSelection => {
14437                    self.request_autoscroll(Autoscroll::fit(), cx);
14438                }
14439                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14440                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14441                }
14442            }
14443        }
14444    }
14445
14446    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14447        if !EditorSettings::get_global(cx).gutter.runnables {
14448            self.clear_tasks();
14449            return Task::ready(());
14450        }
14451        let project = self.project.as_ref().map(Entity::downgrade);
14452        let task_sources = self.lsp_task_sources(cx);
14453        let multi_buffer = self.buffer.downgrade();
14454        cx.spawn_in(window, async move |editor, cx| {
14455            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14456            let Some(project) = project.and_then(|p| p.upgrade()) else {
14457                return;
14458            };
14459            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14460                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14461            }) else {
14462                return;
14463            };
14464
14465            let hide_runnables = project
14466                .update(cx, |project, cx| {
14467                    // Do not display any test indicators in non-dev server remote projects.
14468                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14469                })
14470                .unwrap_or(true);
14471            if hide_runnables {
14472                return;
14473            }
14474            let new_rows =
14475                cx.background_spawn({
14476                    let snapshot = display_snapshot.clone();
14477                    async move {
14478                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14479                    }
14480                })
14481                    .await;
14482            let Ok(lsp_tasks) =
14483                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14484            else {
14485                return;
14486            };
14487            let lsp_tasks = lsp_tasks.await;
14488
14489            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14490                lsp_tasks
14491                    .into_iter()
14492                    .flat_map(|(kind, tasks)| {
14493                        tasks.into_iter().filter_map(move |(location, task)| {
14494                            Some((kind.clone(), location?, task))
14495                        })
14496                    })
14497                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14498                        let buffer = location.target.buffer;
14499                        let buffer_snapshot = buffer.read(cx).snapshot();
14500                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14501                            |(excerpt_id, snapshot, _)| {
14502                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14503                                    display_snapshot
14504                                        .buffer_snapshot
14505                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14506                                } else {
14507                                    None
14508                                }
14509                            },
14510                        );
14511                        if let Some(offset) = offset {
14512                            let task_buffer_range =
14513                                location.target.range.to_point(&buffer_snapshot);
14514                            let context_buffer_range =
14515                                task_buffer_range.to_offset(&buffer_snapshot);
14516                            let context_range = BufferOffset(context_buffer_range.start)
14517                                ..BufferOffset(context_buffer_range.end);
14518
14519                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14520                                .or_insert_with(|| RunnableTasks {
14521                                    templates: Vec::new(),
14522                                    offset,
14523                                    column: task_buffer_range.start.column,
14524                                    extra_variables: HashMap::default(),
14525                                    context_range,
14526                                })
14527                                .templates
14528                                .push((kind, task.original_task().clone()));
14529                        }
14530
14531                        acc
14532                    })
14533            }) else {
14534                return;
14535            };
14536
14537            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14538                buffer.language_settings(cx).tasks.prefer_lsp
14539            }) else {
14540                return;
14541            };
14542
14543            let rows = Self::runnable_rows(
14544                project,
14545                display_snapshot,
14546                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14547                new_rows,
14548                cx.clone(),
14549            )
14550            .await;
14551            editor
14552                .update(cx, |editor, _| {
14553                    editor.clear_tasks();
14554                    for (key, mut value) in rows {
14555                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14556                            value.templates.extend(lsp_tasks.templates);
14557                        }
14558
14559                        editor.insert_tasks(key, value);
14560                    }
14561                    for (key, value) in lsp_tasks_by_rows {
14562                        editor.insert_tasks(key, value);
14563                    }
14564                })
14565                .ok();
14566        })
14567    }
14568    fn fetch_runnable_ranges(
14569        snapshot: &DisplaySnapshot,
14570        range: Range<Anchor>,
14571    ) -> Vec<language::RunnableRange> {
14572        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14573    }
14574
14575    fn runnable_rows(
14576        project: Entity<Project>,
14577        snapshot: DisplaySnapshot,
14578        prefer_lsp: bool,
14579        runnable_ranges: Vec<RunnableRange>,
14580        cx: AsyncWindowContext,
14581    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14582        cx.spawn(async move |cx| {
14583            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14584            for mut runnable in runnable_ranges {
14585                let Some(tasks) = cx
14586                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14587                    .ok()
14588                else {
14589                    continue;
14590                };
14591                let mut tasks = tasks.await;
14592
14593                if prefer_lsp {
14594                    tasks.retain(|(task_kind, _)| {
14595                        !matches!(task_kind, TaskSourceKind::Language { .. })
14596                    });
14597                }
14598                if tasks.is_empty() {
14599                    continue;
14600                }
14601
14602                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14603                let Some(row) = snapshot
14604                    .buffer_snapshot
14605                    .buffer_line_for_row(MultiBufferRow(point.row))
14606                    .map(|(_, range)| range.start.row)
14607                else {
14608                    continue;
14609                };
14610
14611                let context_range =
14612                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14613                runnable_rows.push((
14614                    (runnable.buffer_id, row),
14615                    RunnableTasks {
14616                        templates: tasks,
14617                        offset: snapshot
14618                            .buffer_snapshot
14619                            .anchor_before(runnable.run_range.start),
14620                        context_range,
14621                        column: point.column,
14622                        extra_variables: runnable.extra_captures,
14623                    },
14624                ));
14625            }
14626            runnable_rows
14627        })
14628    }
14629
14630    fn templates_with_tags(
14631        project: &Entity<Project>,
14632        runnable: &mut Runnable,
14633        cx: &mut App,
14634    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14635        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14636            let (worktree_id, file) = project
14637                .buffer_for_id(runnable.buffer, cx)
14638                .and_then(|buffer| buffer.read(cx).file())
14639                .map(|file| (file.worktree_id(cx), file.clone()))
14640                .unzip();
14641
14642            (
14643                project.task_store().read(cx).task_inventory().cloned(),
14644                worktree_id,
14645                file,
14646            )
14647        });
14648
14649        let tags = mem::take(&mut runnable.tags);
14650        let language = runnable.language.clone();
14651        cx.spawn(async move |cx| {
14652            let mut templates_with_tags = Vec::new();
14653            if let Some(inventory) = inventory {
14654                for RunnableTag(tag) in tags {
14655                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14656                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14657                    }) else {
14658                        return templates_with_tags;
14659                    };
14660                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14661                        move |(_, template)| {
14662                            template.tags.iter().any(|source_tag| source_tag == &tag)
14663                        },
14664                    ));
14665                }
14666            }
14667            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14668
14669            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14670                // Strongest source wins; if we have worktree tag binding, prefer that to
14671                // global and language bindings;
14672                // if we have a global binding, prefer that to language binding.
14673                let first_mismatch = templates_with_tags
14674                    .iter()
14675                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14676                if let Some(index) = first_mismatch {
14677                    templates_with_tags.truncate(index);
14678                }
14679            }
14680
14681            templates_with_tags
14682        })
14683    }
14684
14685    pub fn move_to_enclosing_bracket(
14686        &mut self,
14687        _: &MoveToEnclosingBracket,
14688        window: &mut Window,
14689        cx: &mut Context<Self>,
14690    ) {
14691        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14692        self.change_selections(Default::default(), window, cx, |s| {
14693            s.move_offsets_with(|snapshot, selection| {
14694                let Some(enclosing_bracket_ranges) =
14695                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14696                else {
14697                    return;
14698                };
14699
14700                let mut best_length = usize::MAX;
14701                let mut best_inside = false;
14702                let mut best_in_bracket_range = false;
14703                let mut best_destination = None;
14704                for (open, close) in enclosing_bracket_ranges {
14705                    let close = close.to_inclusive();
14706                    let length = close.end() - open.start;
14707                    let inside = selection.start >= open.end && selection.end <= *close.start();
14708                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14709                        || close.contains(&selection.head());
14710
14711                    // If best is next to a bracket and current isn't, skip
14712                    if !in_bracket_range && best_in_bracket_range {
14713                        continue;
14714                    }
14715
14716                    // Prefer smaller lengths unless best is inside and current isn't
14717                    if length > best_length && (best_inside || !inside) {
14718                        continue;
14719                    }
14720
14721                    best_length = length;
14722                    best_inside = inside;
14723                    best_in_bracket_range = in_bracket_range;
14724                    best_destination = Some(
14725                        if close.contains(&selection.start) && close.contains(&selection.end) {
14726                            if inside { open.end } else { open.start }
14727                        } else if inside {
14728                            *close.start()
14729                        } else {
14730                            *close.end()
14731                        },
14732                    );
14733                }
14734
14735                if let Some(destination) = best_destination {
14736                    selection.collapse_to(destination, SelectionGoal::None);
14737                }
14738            })
14739        });
14740    }
14741
14742    pub fn undo_selection(
14743        &mut self,
14744        _: &UndoSelection,
14745        window: &mut Window,
14746        cx: &mut Context<Self>,
14747    ) {
14748        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14749        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14750            self.selection_history.mode = SelectionHistoryMode::Undoing;
14751            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14752                this.end_selection(window, cx);
14753                this.change_selections(
14754                    SelectionEffects::scroll(Autoscroll::newest()),
14755                    window,
14756                    cx,
14757                    |s| s.select_anchors(entry.selections.to_vec()),
14758                );
14759            });
14760            self.selection_history.mode = SelectionHistoryMode::Normal;
14761
14762            self.select_next_state = entry.select_next_state;
14763            self.select_prev_state = entry.select_prev_state;
14764            self.add_selections_state = entry.add_selections_state;
14765        }
14766    }
14767
14768    pub fn redo_selection(
14769        &mut self,
14770        _: &RedoSelection,
14771        window: &mut Window,
14772        cx: &mut Context<Self>,
14773    ) {
14774        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14775        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14776            self.selection_history.mode = SelectionHistoryMode::Redoing;
14777            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14778                this.end_selection(window, cx);
14779                this.change_selections(
14780                    SelectionEffects::scroll(Autoscroll::newest()),
14781                    window,
14782                    cx,
14783                    |s| s.select_anchors(entry.selections.to_vec()),
14784                );
14785            });
14786            self.selection_history.mode = SelectionHistoryMode::Normal;
14787
14788            self.select_next_state = entry.select_next_state;
14789            self.select_prev_state = entry.select_prev_state;
14790            self.add_selections_state = entry.add_selections_state;
14791        }
14792    }
14793
14794    pub fn expand_excerpts(
14795        &mut self,
14796        action: &ExpandExcerpts,
14797        _: &mut Window,
14798        cx: &mut Context<Self>,
14799    ) {
14800        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14801    }
14802
14803    pub fn expand_excerpts_down(
14804        &mut self,
14805        action: &ExpandExcerptsDown,
14806        _: &mut Window,
14807        cx: &mut Context<Self>,
14808    ) {
14809        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14810    }
14811
14812    pub fn expand_excerpts_up(
14813        &mut self,
14814        action: &ExpandExcerptsUp,
14815        _: &mut Window,
14816        cx: &mut Context<Self>,
14817    ) {
14818        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14819    }
14820
14821    pub fn expand_excerpts_for_direction(
14822        &mut self,
14823        lines: u32,
14824        direction: ExpandExcerptDirection,
14825
14826        cx: &mut Context<Self>,
14827    ) {
14828        let selections = self.selections.disjoint_anchors();
14829
14830        let lines = if lines == 0 {
14831            EditorSettings::get_global(cx).expand_excerpt_lines
14832        } else {
14833            lines
14834        };
14835
14836        self.buffer.update(cx, |buffer, cx| {
14837            let snapshot = buffer.snapshot(cx);
14838            let mut excerpt_ids = selections
14839                .iter()
14840                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14841                .collect::<Vec<_>>();
14842            excerpt_ids.sort();
14843            excerpt_ids.dedup();
14844            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14845        })
14846    }
14847
14848    pub fn expand_excerpt(
14849        &mut self,
14850        excerpt: ExcerptId,
14851        direction: ExpandExcerptDirection,
14852        window: &mut Window,
14853        cx: &mut Context<Self>,
14854    ) {
14855        let current_scroll_position = self.scroll_position(cx);
14856        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14857        let mut should_scroll_up = false;
14858
14859        if direction == ExpandExcerptDirection::Down {
14860            let multi_buffer = self.buffer.read(cx);
14861            let snapshot = multi_buffer.snapshot(cx);
14862            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14863                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14864                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14865                        let buffer_snapshot = buffer.read(cx).snapshot();
14866                        let excerpt_end_row =
14867                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14868                        let last_row = buffer_snapshot.max_point().row;
14869                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14870                        should_scroll_up = lines_below >= lines_to_expand;
14871                    }
14872                }
14873            }
14874        }
14875
14876        self.buffer.update(cx, |buffer, cx| {
14877            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14878        });
14879
14880        if should_scroll_up {
14881            let new_scroll_position =
14882                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14883            self.set_scroll_position(new_scroll_position, window, cx);
14884        }
14885    }
14886
14887    pub fn go_to_singleton_buffer_point(
14888        &mut self,
14889        point: Point,
14890        window: &mut Window,
14891        cx: &mut Context<Self>,
14892    ) {
14893        self.go_to_singleton_buffer_range(point..point, window, cx);
14894    }
14895
14896    pub fn go_to_singleton_buffer_range(
14897        &mut self,
14898        range: Range<Point>,
14899        window: &mut Window,
14900        cx: &mut Context<Self>,
14901    ) {
14902        let multibuffer = self.buffer().read(cx);
14903        let Some(buffer) = multibuffer.as_singleton() else {
14904            return;
14905        };
14906        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14907            return;
14908        };
14909        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14910            return;
14911        };
14912        self.change_selections(
14913            SelectionEffects::default().nav_history(true),
14914            window,
14915            cx,
14916            |s| s.select_anchor_ranges([start..end]),
14917        );
14918    }
14919
14920    pub fn go_to_diagnostic(
14921        &mut self,
14922        _: &GoToDiagnostic,
14923        window: &mut Window,
14924        cx: &mut Context<Self>,
14925    ) {
14926        if !self.diagnostics_enabled() {
14927            return;
14928        }
14929        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14930        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14931    }
14932
14933    pub fn go_to_prev_diagnostic(
14934        &mut self,
14935        _: &GoToPreviousDiagnostic,
14936        window: &mut Window,
14937        cx: &mut Context<Self>,
14938    ) {
14939        if !self.diagnostics_enabled() {
14940            return;
14941        }
14942        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14943        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14944    }
14945
14946    pub fn go_to_diagnostic_impl(
14947        &mut self,
14948        direction: Direction,
14949        window: &mut Window,
14950        cx: &mut Context<Self>,
14951    ) {
14952        let buffer = self.buffer.read(cx).snapshot(cx);
14953        let selection = self.selections.newest::<usize>(cx);
14954
14955        let mut active_group_id = None;
14956        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14957            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14958                active_group_id = Some(active_group.group_id);
14959            }
14960        }
14961
14962        fn filtered(
14963            snapshot: EditorSnapshot,
14964            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14965        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14966            diagnostics
14967                .filter(|entry| entry.range.start != entry.range.end)
14968                .filter(|entry| !entry.diagnostic.is_unnecessary)
14969                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14970        }
14971
14972        let snapshot = self.snapshot(window, cx);
14973        let before = filtered(
14974            snapshot.clone(),
14975            buffer
14976                .diagnostics_in_range(0..selection.start)
14977                .filter(|entry| entry.range.start <= selection.start),
14978        );
14979        let after = filtered(
14980            snapshot,
14981            buffer
14982                .diagnostics_in_range(selection.start..buffer.len())
14983                .filter(|entry| entry.range.start >= selection.start),
14984        );
14985
14986        let mut found: Option<DiagnosticEntry<usize>> = None;
14987        if direction == Direction::Prev {
14988            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14989            {
14990                for diagnostic in prev_diagnostics.into_iter().rev() {
14991                    if diagnostic.range.start != selection.start
14992                        || active_group_id
14993                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14994                    {
14995                        found = Some(diagnostic);
14996                        break 'outer;
14997                    }
14998                }
14999            }
15000        } else {
15001            for diagnostic in after.chain(before) {
15002                if diagnostic.range.start != selection.start
15003                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15004                {
15005                    found = Some(diagnostic);
15006                    break;
15007                }
15008            }
15009        }
15010        let Some(next_diagnostic) = found else {
15011            return;
15012        };
15013
15014        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15015            return;
15016        };
15017        self.change_selections(Default::default(), window, cx, |s| {
15018            s.select_ranges(vec![
15019                next_diagnostic.range.start..next_diagnostic.range.start,
15020            ])
15021        });
15022        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15023        self.refresh_inline_completion(false, true, window, cx);
15024    }
15025
15026    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15027        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15028        let snapshot = self.snapshot(window, cx);
15029        let selection = self.selections.newest::<Point>(cx);
15030        self.go_to_hunk_before_or_after_position(
15031            &snapshot,
15032            selection.head(),
15033            Direction::Next,
15034            window,
15035            cx,
15036        );
15037    }
15038
15039    pub fn go_to_hunk_before_or_after_position(
15040        &mut self,
15041        snapshot: &EditorSnapshot,
15042        position: Point,
15043        direction: Direction,
15044        window: &mut Window,
15045        cx: &mut Context<Editor>,
15046    ) {
15047        let row = if direction == Direction::Next {
15048            self.hunk_after_position(snapshot, position)
15049                .map(|hunk| hunk.row_range.start)
15050        } else {
15051            self.hunk_before_position(snapshot, position)
15052        };
15053
15054        if let Some(row) = row {
15055            let destination = Point::new(row.0, 0);
15056            let autoscroll = Autoscroll::center();
15057
15058            self.unfold_ranges(&[destination..destination], false, false, cx);
15059            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15060                s.select_ranges([destination..destination]);
15061            });
15062        }
15063    }
15064
15065    fn hunk_after_position(
15066        &mut self,
15067        snapshot: &EditorSnapshot,
15068        position: Point,
15069    ) -> Option<MultiBufferDiffHunk> {
15070        snapshot
15071            .buffer_snapshot
15072            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15073            .find(|hunk| hunk.row_range.start.0 > position.row)
15074            .or_else(|| {
15075                snapshot
15076                    .buffer_snapshot
15077                    .diff_hunks_in_range(Point::zero()..position)
15078                    .find(|hunk| hunk.row_range.end.0 < position.row)
15079            })
15080    }
15081
15082    fn go_to_prev_hunk(
15083        &mut self,
15084        _: &GoToPreviousHunk,
15085        window: &mut Window,
15086        cx: &mut Context<Self>,
15087    ) {
15088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15089        let snapshot = self.snapshot(window, cx);
15090        let selection = self.selections.newest::<Point>(cx);
15091        self.go_to_hunk_before_or_after_position(
15092            &snapshot,
15093            selection.head(),
15094            Direction::Prev,
15095            window,
15096            cx,
15097        );
15098    }
15099
15100    fn hunk_before_position(
15101        &mut self,
15102        snapshot: &EditorSnapshot,
15103        position: Point,
15104    ) -> Option<MultiBufferRow> {
15105        snapshot
15106            .buffer_snapshot
15107            .diff_hunk_before(position)
15108            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15109    }
15110
15111    fn go_to_next_change(
15112        &mut self,
15113        _: &GoToNextChange,
15114        window: &mut Window,
15115        cx: &mut Context<Self>,
15116    ) {
15117        if let Some(selections) = self
15118            .change_list
15119            .next_change(1, Direction::Next)
15120            .map(|s| s.to_vec())
15121        {
15122            self.change_selections(Default::default(), window, cx, |s| {
15123                let map = s.display_map();
15124                s.select_display_ranges(selections.iter().map(|a| {
15125                    let point = a.to_display_point(&map);
15126                    point..point
15127                }))
15128            })
15129        }
15130    }
15131
15132    fn go_to_previous_change(
15133        &mut self,
15134        _: &GoToPreviousChange,
15135        window: &mut Window,
15136        cx: &mut Context<Self>,
15137    ) {
15138        if let Some(selections) = self
15139            .change_list
15140            .next_change(1, Direction::Prev)
15141            .map(|s| s.to_vec())
15142        {
15143            self.change_selections(Default::default(), window, cx, |s| {
15144                let map = s.display_map();
15145                s.select_display_ranges(selections.iter().map(|a| {
15146                    let point = a.to_display_point(&map);
15147                    point..point
15148                }))
15149            })
15150        }
15151    }
15152
15153    fn go_to_line<T: 'static>(
15154        &mut self,
15155        position: Anchor,
15156        highlight_color: Option<Hsla>,
15157        window: &mut Window,
15158        cx: &mut Context<Self>,
15159    ) {
15160        let snapshot = self.snapshot(window, cx).display_snapshot;
15161        let position = position.to_point(&snapshot.buffer_snapshot);
15162        let start = snapshot
15163            .buffer_snapshot
15164            .clip_point(Point::new(position.row, 0), Bias::Left);
15165        let end = start + Point::new(1, 0);
15166        let start = snapshot.buffer_snapshot.anchor_before(start);
15167        let end = snapshot.buffer_snapshot.anchor_before(end);
15168
15169        self.highlight_rows::<T>(
15170            start..end,
15171            highlight_color
15172                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15173            Default::default(),
15174            cx,
15175        );
15176
15177        if self.buffer.read(cx).is_singleton() {
15178            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15179        }
15180    }
15181
15182    pub fn go_to_definition(
15183        &mut self,
15184        _: &GoToDefinition,
15185        window: &mut Window,
15186        cx: &mut Context<Self>,
15187    ) -> Task<Result<Navigated>> {
15188        let definition =
15189            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15190        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15191        cx.spawn_in(window, async move |editor, cx| {
15192            if definition.await? == Navigated::Yes {
15193                return Ok(Navigated::Yes);
15194            }
15195            match fallback_strategy {
15196                GoToDefinitionFallback::None => Ok(Navigated::No),
15197                GoToDefinitionFallback::FindAllReferences => {
15198                    match editor.update_in(cx, |editor, window, cx| {
15199                        editor.find_all_references(&FindAllReferences, window, cx)
15200                    })? {
15201                        Some(references) => references.await,
15202                        None => Ok(Navigated::No),
15203                    }
15204                }
15205            }
15206        })
15207    }
15208
15209    pub fn go_to_declaration(
15210        &mut self,
15211        _: &GoToDeclaration,
15212        window: &mut Window,
15213        cx: &mut Context<Self>,
15214    ) -> Task<Result<Navigated>> {
15215        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15216    }
15217
15218    pub fn go_to_declaration_split(
15219        &mut self,
15220        _: &GoToDeclaration,
15221        window: &mut Window,
15222        cx: &mut Context<Self>,
15223    ) -> Task<Result<Navigated>> {
15224        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15225    }
15226
15227    pub fn go_to_implementation(
15228        &mut self,
15229        _: &GoToImplementation,
15230        window: &mut Window,
15231        cx: &mut Context<Self>,
15232    ) -> Task<Result<Navigated>> {
15233        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15234    }
15235
15236    pub fn go_to_implementation_split(
15237        &mut self,
15238        _: &GoToImplementationSplit,
15239        window: &mut Window,
15240        cx: &mut Context<Self>,
15241    ) -> Task<Result<Navigated>> {
15242        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15243    }
15244
15245    pub fn go_to_type_definition(
15246        &mut self,
15247        _: &GoToTypeDefinition,
15248        window: &mut Window,
15249        cx: &mut Context<Self>,
15250    ) -> Task<Result<Navigated>> {
15251        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15252    }
15253
15254    pub fn go_to_definition_split(
15255        &mut self,
15256        _: &GoToDefinitionSplit,
15257        window: &mut Window,
15258        cx: &mut Context<Self>,
15259    ) -> Task<Result<Navigated>> {
15260        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15261    }
15262
15263    pub fn go_to_type_definition_split(
15264        &mut self,
15265        _: &GoToTypeDefinitionSplit,
15266        window: &mut Window,
15267        cx: &mut Context<Self>,
15268    ) -> Task<Result<Navigated>> {
15269        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15270    }
15271
15272    fn go_to_definition_of_kind(
15273        &mut self,
15274        kind: GotoDefinitionKind,
15275        split: bool,
15276        window: &mut Window,
15277        cx: &mut Context<Self>,
15278    ) -> Task<Result<Navigated>> {
15279        let Some(provider) = self.semantics_provider.clone() else {
15280            return Task::ready(Ok(Navigated::No));
15281        };
15282        let head = self.selections.newest::<usize>(cx).head();
15283        let buffer = self.buffer.read(cx);
15284        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15285            text_anchor
15286        } else {
15287            return Task::ready(Ok(Navigated::No));
15288        };
15289
15290        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15291            return Task::ready(Ok(Navigated::No));
15292        };
15293
15294        cx.spawn_in(window, async move |editor, cx| {
15295            let definitions = definitions.await?;
15296            let navigated = editor
15297                .update_in(cx, |editor, window, cx| {
15298                    editor.navigate_to_hover_links(
15299                        Some(kind),
15300                        definitions
15301                            .into_iter()
15302                            .filter(|location| {
15303                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15304                            })
15305                            .map(HoverLink::Text)
15306                            .collect::<Vec<_>>(),
15307                        split,
15308                        window,
15309                        cx,
15310                    )
15311                })?
15312                .await?;
15313            anyhow::Ok(navigated)
15314        })
15315    }
15316
15317    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15318        let selection = self.selections.newest_anchor();
15319        let head = selection.head();
15320        let tail = selection.tail();
15321
15322        let Some((buffer, start_position)) =
15323            self.buffer.read(cx).text_anchor_for_position(head, cx)
15324        else {
15325            return;
15326        };
15327
15328        let end_position = if head != tail {
15329            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15330                return;
15331            };
15332            Some(pos)
15333        } else {
15334            None
15335        };
15336
15337        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15338            let url = if let Some(end_pos) = end_position {
15339                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15340            } else {
15341                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15342            };
15343
15344            if let Some(url) = url {
15345                editor.update(cx, |_, cx| {
15346                    cx.open_url(&url);
15347                })
15348            } else {
15349                Ok(())
15350            }
15351        });
15352
15353        url_finder.detach();
15354    }
15355
15356    pub fn open_selected_filename(
15357        &mut self,
15358        _: &OpenSelectedFilename,
15359        window: &mut Window,
15360        cx: &mut Context<Self>,
15361    ) {
15362        let Some(workspace) = self.workspace() else {
15363            return;
15364        };
15365
15366        let position = self.selections.newest_anchor().head();
15367
15368        let Some((buffer, buffer_position)) =
15369            self.buffer.read(cx).text_anchor_for_position(position, cx)
15370        else {
15371            return;
15372        };
15373
15374        let project = self.project.clone();
15375
15376        cx.spawn_in(window, async move |_, cx| {
15377            let result = find_file(&buffer, project, buffer_position, cx).await;
15378
15379            if let Some((_, path)) = result {
15380                workspace
15381                    .update_in(cx, |workspace, window, cx| {
15382                        workspace.open_resolved_path(path, window, cx)
15383                    })?
15384                    .await?;
15385            }
15386            anyhow::Ok(())
15387        })
15388        .detach();
15389    }
15390
15391    pub(crate) fn navigate_to_hover_links(
15392        &mut self,
15393        kind: Option<GotoDefinitionKind>,
15394        mut definitions: Vec<HoverLink>,
15395        split: bool,
15396        window: &mut Window,
15397        cx: &mut Context<Editor>,
15398    ) -> Task<Result<Navigated>> {
15399        // If there is one definition, just open it directly
15400        if definitions.len() == 1 {
15401            let definition = definitions.pop().unwrap();
15402
15403            enum TargetTaskResult {
15404                Location(Option<Location>),
15405                AlreadyNavigated,
15406            }
15407
15408            let target_task = match definition {
15409                HoverLink::Text(link) => {
15410                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15411                }
15412                HoverLink::InlayHint(lsp_location, server_id) => {
15413                    let computation =
15414                        self.compute_target_location(lsp_location, server_id, window, cx);
15415                    cx.background_spawn(async move {
15416                        let location = computation.await?;
15417                        Ok(TargetTaskResult::Location(location))
15418                    })
15419                }
15420                HoverLink::Url(url) => {
15421                    cx.open_url(&url);
15422                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15423                }
15424                HoverLink::File(path) => {
15425                    if let Some(workspace) = self.workspace() {
15426                        cx.spawn_in(window, async move |_, cx| {
15427                            workspace
15428                                .update_in(cx, |workspace, window, cx| {
15429                                    workspace.open_resolved_path(path, window, cx)
15430                                })?
15431                                .await
15432                                .map(|_| TargetTaskResult::AlreadyNavigated)
15433                        })
15434                    } else {
15435                        Task::ready(Ok(TargetTaskResult::Location(None)))
15436                    }
15437                }
15438            };
15439            cx.spawn_in(window, async move |editor, cx| {
15440                let target = match target_task.await.context("target resolution task")? {
15441                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15442                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15443                    TargetTaskResult::Location(Some(target)) => target,
15444                };
15445
15446                editor.update_in(cx, |editor, window, cx| {
15447                    let Some(workspace) = editor.workspace() else {
15448                        return Navigated::No;
15449                    };
15450                    let pane = workspace.read(cx).active_pane().clone();
15451
15452                    let range = target.range.to_point(target.buffer.read(cx));
15453                    let range = editor.range_for_match(&range);
15454                    let range = collapse_multiline_range(range);
15455
15456                    if !split
15457                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15458                    {
15459                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15460                    } else {
15461                        window.defer(cx, move |window, cx| {
15462                            let target_editor: Entity<Self> =
15463                                workspace.update(cx, |workspace, cx| {
15464                                    let pane = if split {
15465                                        workspace.adjacent_pane(window, cx)
15466                                    } else {
15467                                        workspace.active_pane().clone()
15468                                    };
15469
15470                                    workspace.open_project_item(
15471                                        pane,
15472                                        target.buffer.clone(),
15473                                        true,
15474                                        true,
15475                                        window,
15476                                        cx,
15477                                    )
15478                                });
15479                            target_editor.update(cx, |target_editor, cx| {
15480                                // When selecting a definition in a different buffer, disable the nav history
15481                                // to avoid creating a history entry at the previous cursor location.
15482                                pane.update(cx, |pane, _| pane.disable_history());
15483                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15484                                pane.update(cx, |pane, _| pane.enable_history());
15485                            });
15486                        });
15487                    }
15488                    Navigated::Yes
15489                })
15490            })
15491        } else if !definitions.is_empty() {
15492            cx.spawn_in(window, async move |editor, cx| {
15493                let (title, location_tasks, workspace) = editor
15494                    .update_in(cx, |editor, window, cx| {
15495                        let tab_kind = match kind {
15496                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15497                            _ => "Definitions",
15498                        };
15499                        let title = definitions
15500                            .iter()
15501                            .find_map(|definition| match definition {
15502                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15503                                    let buffer = origin.buffer.read(cx);
15504                                    format!(
15505                                        "{} for {}",
15506                                        tab_kind,
15507                                        buffer
15508                                            .text_for_range(origin.range.clone())
15509                                            .collect::<String>()
15510                                    )
15511                                }),
15512                                HoverLink::InlayHint(_, _) => None,
15513                                HoverLink::Url(_) => None,
15514                                HoverLink::File(_) => None,
15515                            })
15516                            .unwrap_or(tab_kind.to_string());
15517                        let location_tasks = definitions
15518                            .into_iter()
15519                            .map(|definition| match definition {
15520                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15521                                HoverLink::InlayHint(lsp_location, server_id) => editor
15522                                    .compute_target_location(lsp_location, server_id, window, cx),
15523                                HoverLink::Url(_) => Task::ready(Ok(None)),
15524                                HoverLink::File(_) => Task::ready(Ok(None)),
15525                            })
15526                            .collect::<Vec<_>>();
15527                        (title, location_tasks, editor.workspace().clone())
15528                    })
15529                    .context("location tasks preparation")?;
15530
15531                let locations: Vec<Location> = future::join_all(location_tasks)
15532                    .await
15533                    .into_iter()
15534                    .filter_map(|location| location.transpose())
15535                    .collect::<Result<_>>()
15536                    .context("location tasks")?;
15537
15538                if locations.is_empty() {
15539                    return Ok(Navigated::No);
15540                }
15541
15542                let Some(workspace) = workspace else {
15543                    return Ok(Navigated::No);
15544                };
15545
15546                let opened = workspace
15547                    .update_in(cx, |workspace, window, cx| {
15548                        Self::open_locations_in_multibuffer(
15549                            workspace,
15550                            locations,
15551                            title,
15552                            split,
15553                            MultibufferSelectionMode::First,
15554                            window,
15555                            cx,
15556                        )
15557                    })
15558                    .ok();
15559
15560                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15561            })
15562        } else {
15563            Task::ready(Ok(Navigated::No))
15564        }
15565    }
15566
15567    fn compute_target_location(
15568        &self,
15569        lsp_location: lsp::Location,
15570        server_id: LanguageServerId,
15571        window: &mut Window,
15572        cx: &mut Context<Self>,
15573    ) -> Task<anyhow::Result<Option<Location>>> {
15574        let Some(project) = self.project.clone() else {
15575            return Task::ready(Ok(None));
15576        };
15577
15578        cx.spawn_in(window, async move |editor, cx| {
15579            let location_task = editor.update(cx, |_, cx| {
15580                project.update(cx, |project, cx| {
15581                    let language_server_name = project
15582                        .language_server_statuses(cx)
15583                        .find(|(id, _)| server_id == *id)
15584                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15585                    language_server_name.map(|language_server_name| {
15586                        project.open_local_buffer_via_lsp(
15587                            lsp_location.uri.clone(),
15588                            server_id,
15589                            language_server_name,
15590                            cx,
15591                        )
15592                    })
15593                })
15594            })?;
15595            let location = match location_task {
15596                Some(task) => Some({
15597                    let target_buffer_handle = task.await.context("open local buffer")?;
15598                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15599                        let target_start = target_buffer
15600                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15601                        let target_end = target_buffer
15602                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15603                        target_buffer.anchor_after(target_start)
15604                            ..target_buffer.anchor_before(target_end)
15605                    })?;
15606                    Location {
15607                        buffer: target_buffer_handle,
15608                        range,
15609                    }
15610                }),
15611                None => None,
15612            };
15613            Ok(location)
15614        })
15615    }
15616
15617    pub fn find_all_references(
15618        &mut self,
15619        _: &FindAllReferences,
15620        window: &mut Window,
15621        cx: &mut Context<Self>,
15622    ) -> Option<Task<Result<Navigated>>> {
15623        let selection = self.selections.newest::<usize>(cx);
15624        let multi_buffer = self.buffer.read(cx);
15625        let head = selection.head();
15626
15627        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15628        let head_anchor = multi_buffer_snapshot.anchor_at(
15629            head,
15630            if head < selection.tail() {
15631                Bias::Right
15632            } else {
15633                Bias::Left
15634            },
15635        );
15636
15637        match self
15638            .find_all_references_task_sources
15639            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15640        {
15641            Ok(_) => {
15642                log::info!(
15643                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15644                );
15645                return None;
15646            }
15647            Err(i) => {
15648                self.find_all_references_task_sources.insert(i, head_anchor);
15649            }
15650        }
15651
15652        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15653        let workspace = self.workspace()?;
15654        let project = workspace.read(cx).project().clone();
15655        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15656        Some(cx.spawn_in(window, async move |editor, cx| {
15657            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15658                if let Ok(i) = editor
15659                    .find_all_references_task_sources
15660                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15661                {
15662                    editor.find_all_references_task_sources.remove(i);
15663                }
15664            });
15665
15666            let locations = references.await?;
15667            if locations.is_empty() {
15668                return anyhow::Ok(Navigated::No);
15669            }
15670
15671            workspace.update_in(cx, |workspace, window, cx| {
15672                let title = locations
15673                    .first()
15674                    .as_ref()
15675                    .map(|location| {
15676                        let buffer = location.buffer.read(cx);
15677                        format!(
15678                            "References to `{}`",
15679                            buffer
15680                                .text_for_range(location.range.clone())
15681                                .collect::<String>()
15682                        )
15683                    })
15684                    .unwrap();
15685                Self::open_locations_in_multibuffer(
15686                    workspace,
15687                    locations,
15688                    title,
15689                    false,
15690                    MultibufferSelectionMode::First,
15691                    window,
15692                    cx,
15693                );
15694                Navigated::Yes
15695            })
15696        }))
15697    }
15698
15699    /// Opens a multibuffer with the given project locations in it
15700    pub fn open_locations_in_multibuffer(
15701        workspace: &mut Workspace,
15702        mut locations: Vec<Location>,
15703        title: String,
15704        split: bool,
15705        multibuffer_selection_mode: MultibufferSelectionMode,
15706        window: &mut Window,
15707        cx: &mut Context<Workspace>,
15708    ) {
15709        if locations.is_empty() {
15710            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15711            return;
15712        }
15713
15714        // If there are multiple definitions, open them in a multibuffer
15715        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15716        let mut locations = locations.into_iter().peekable();
15717        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15718        let capability = workspace.project().read(cx).capability();
15719
15720        let excerpt_buffer = cx.new(|cx| {
15721            let mut multibuffer = MultiBuffer::new(capability);
15722            while let Some(location) = locations.next() {
15723                let buffer = location.buffer.read(cx);
15724                let mut ranges_for_buffer = Vec::new();
15725                let range = location.range.to_point(buffer);
15726                ranges_for_buffer.push(range.clone());
15727
15728                while let Some(next_location) = locations.peek() {
15729                    if next_location.buffer == location.buffer {
15730                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15731                        locations.next();
15732                    } else {
15733                        break;
15734                    }
15735                }
15736
15737                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15738                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15739                    PathKey::for_buffer(&location.buffer, cx),
15740                    location.buffer.clone(),
15741                    ranges_for_buffer,
15742                    DEFAULT_MULTIBUFFER_CONTEXT,
15743                    cx,
15744                );
15745                ranges.extend(new_ranges)
15746            }
15747
15748            multibuffer.with_title(title)
15749        });
15750
15751        let editor = cx.new(|cx| {
15752            Editor::for_multibuffer(
15753                excerpt_buffer,
15754                Some(workspace.project().clone()),
15755                window,
15756                cx,
15757            )
15758        });
15759        editor.update(cx, |editor, cx| {
15760            match multibuffer_selection_mode {
15761                MultibufferSelectionMode::First => {
15762                    if let Some(first_range) = ranges.first() {
15763                        editor.change_selections(
15764                            SelectionEffects::no_scroll(),
15765                            window,
15766                            cx,
15767                            |selections| {
15768                                selections.clear_disjoint();
15769                                selections
15770                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15771                            },
15772                        );
15773                    }
15774                    editor.highlight_background::<Self>(
15775                        &ranges,
15776                        |theme| theme.colors().editor_highlighted_line_background,
15777                        cx,
15778                    );
15779                }
15780                MultibufferSelectionMode::All => {
15781                    editor.change_selections(
15782                        SelectionEffects::no_scroll(),
15783                        window,
15784                        cx,
15785                        |selections| {
15786                            selections.clear_disjoint();
15787                            selections.select_anchor_ranges(ranges);
15788                        },
15789                    );
15790                }
15791            }
15792            editor.register_buffers_with_language_servers(cx);
15793        });
15794
15795        let item = Box::new(editor);
15796        let item_id = item.item_id();
15797
15798        if split {
15799            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15800        } else {
15801            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15802                let (preview_item_id, preview_item_idx) =
15803                    workspace.active_pane().read_with(cx, |pane, _| {
15804                        (pane.preview_item_id(), pane.preview_item_idx())
15805                    });
15806
15807                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15808
15809                if let Some(preview_item_id) = preview_item_id {
15810                    workspace.active_pane().update(cx, |pane, cx| {
15811                        pane.remove_item(preview_item_id, false, false, window, cx);
15812                    });
15813                }
15814            } else {
15815                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15816            }
15817        }
15818        workspace.active_pane().update(cx, |pane, cx| {
15819            pane.set_preview_item_id(Some(item_id), cx);
15820        });
15821    }
15822
15823    pub fn rename(
15824        &mut self,
15825        _: &Rename,
15826        window: &mut Window,
15827        cx: &mut Context<Self>,
15828    ) -> Option<Task<Result<()>>> {
15829        use language::ToOffset as _;
15830
15831        let provider = self.semantics_provider.clone()?;
15832        let selection = self.selections.newest_anchor().clone();
15833        let (cursor_buffer, cursor_buffer_position) = self
15834            .buffer
15835            .read(cx)
15836            .text_anchor_for_position(selection.head(), cx)?;
15837        let (tail_buffer, cursor_buffer_position_end) = self
15838            .buffer
15839            .read(cx)
15840            .text_anchor_for_position(selection.tail(), cx)?;
15841        if tail_buffer != cursor_buffer {
15842            return None;
15843        }
15844
15845        let snapshot = cursor_buffer.read(cx).snapshot();
15846        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15847        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15848        let prepare_rename = provider
15849            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15850            .unwrap_or_else(|| Task::ready(Ok(None)));
15851        drop(snapshot);
15852
15853        Some(cx.spawn_in(window, async move |this, cx| {
15854            let rename_range = if let Some(range) = prepare_rename.await? {
15855                Some(range)
15856            } else {
15857                this.update(cx, |this, cx| {
15858                    let buffer = this.buffer.read(cx).snapshot(cx);
15859                    let mut buffer_highlights = this
15860                        .document_highlights_for_position(selection.head(), &buffer)
15861                        .filter(|highlight| {
15862                            highlight.start.excerpt_id == selection.head().excerpt_id
15863                                && highlight.end.excerpt_id == selection.head().excerpt_id
15864                        });
15865                    buffer_highlights
15866                        .next()
15867                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15868                })?
15869            };
15870            if let Some(rename_range) = rename_range {
15871                this.update_in(cx, |this, window, cx| {
15872                    let snapshot = cursor_buffer.read(cx).snapshot();
15873                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15874                    let cursor_offset_in_rename_range =
15875                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15876                    let cursor_offset_in_rename_range_end =
15877                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15878
15879                    this.take_rename(false, window, cx);
15880                    let buffer = this.buffer.read(cx).read(cx);
15881                    let cursor_offset = selection.head().to_offset(&buffer);
15882                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15883                    let rename_end = rename_start + rename_buffer_range.len();
15884                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15885                    let mut old_highlight_id = None;
15886                    let old_name: Arc<str> = buffer
15887                        .chunks(rename_start..rename_end, true)
15888                        .map(|chunk| {
15889                            if old_highlight_id.is_none() {
15890                                old_highlight_id = chunk.syntax_highlight_id;
15891                            }
15892                            chunk.text
15893                        })
15894                        .collect::<String>()
15895                        .into();
15896
15897                    drop(buffer);
15898
15899                    // Position the selection in the rename editor so that it matches the current selection.
15900                    this.show_local_selections = false;
15901                    let rename_editor = cx.new(|cx| {
15902                        let mut editor = Editor::single_line(window, cx);
15903                        editor.buffer.update(cx, |buffer, cx| {
15904                            buffer.edit([(0..0, old_name.clone())], None, cx)
15905                        });
15906                        let rename_selection_range = match cursor_offset_in_rename_range
15907                            .cmp(&cursor_offset_in_rename_range_end)
15908                        {
15909                            Ordering::Equal => {
15910                                editor.select_all(&SelectAll, window, cx);
15911                                return editor;
15912                            }
15913                            Ordering::Less => {
15914                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15915                            }
15916                            Ordering::Greater => {
15917                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15918                            }
15919                        };
15920                        if rename_selection_range.end > old_name.len() {
15921                            editor.select_all(&SelectAll, window, cx);
15922                        } else {
15923                            editor.change_selections(Default::default(), window, cx, |s| {
15924                                s.select_ranges([rename_selection_range]);
15925                            });
15926                        }
15927                        editor
15928                    });
15929                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15930                        if e == &EditorEvent::Focused {
15931                            cx.emit(EditorEvent::FocusedIn)
15932                        }
15933                    })
15934                    .detach();
15935
15936                    let write_highlights =
15937                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15938                    let read_highlights =
15939                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15940                    let ranges = write_highlights
15941                        .iter()
15942                        .flat_map(|(_, ranges)| ranges.iter())
15943                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15944                        .cloned()
15945                        .collect();
15946
15947                    this.highlight_text::<Rename>(
15948                        ranges,
15949                        HighlightStyle {
15950                            fade_out: Some(0.6),
15951                            ..Default::default()
15952                        },
15953                        cx,
15954                    );
15955                    let rename_focus_handle = rename_editor.focus_handle(cx);
15956                    window.focus(&rename_focus_handle);
15957                    let block_id = this.insert_blocks(
15958                        [BlockProperties {
15959                            style: BlockStyle::Flex,
15960                            placement: BlockPlacement::Below(range.start),
15961                            height: Some(1),
15962                            render: Arc::new({
15963                                let rename_editor = rename_editor.clone();
15964                                move |cx: &mut BlockContext| {
15965                                    let mut text_style = cx.editor_style.text.clone();
15966                                    if let Some(highlight_style) = old_highlight_id
15967                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15968                                    {
15969                                        text_style = text_style.highlight(highlight_style);
15970                                    }
15971                                    div()
15972                                        .block_mouse_except_scroll()
15973                                        .pl(cx.anchor_x)
15974                                        .child(EditorElement::new(
15975                                            &rename_editor,
15976                                            EditorStyle {
15977                                                background: cx.theme().system().transparent,
15978                                                local_player: cx.editor_style.local_player,
15979                                                text: text_style,
15980                                                scrollbar_width: cx.editor_style.scrollbar_width,
15981                                                syntax: cx.editor_style.syntax.clone(),
15982                                                status: cx.editor_style.status.clone(),
15983                                                inlay_hints_style: HighlightStyle {
15984                                                    font_weight: Some(FontWeight::BOLD),
15985                                                    ..make_inlay_hints_style(cx.app)
15986                                                },
15987                                                inline_completion_styles: make_suggestion_styles(
15988                                                    cx.app,
15989                                                ),
15990                                                ..EditorStyle::default()
15991                                            },
15992                                        ))
15993                                        .into_any_element()
15994                                }
15995                            }),
15996                            priority: 0,
15997                            render_in_minimap: true,
15998                        }],
15999                        Some(Autoscroll::fit()),
16000                        cx,
16001                    )[0];
16002                    this.pending_rename = Some(RenameState {
16003                        range,
16004                        old_name,
16005                        editor: rename_editor,
16006                        block_id,
16007                    });
16008                })?;
16009            }
16010
16011            Ok(())
16012        }))
16013    }
16014
16015    pub fn confirm_rename(
16016        &mut self,
16017        _: &ConfirmRename,
16018        window: &mut Window,
16019        cx: &mut Context<Self>,
16020    ) -> Option<Task<Result<()>>> {
16021        let rename = self.take_rename(false, window, cx)?;
16022        let workspace = self.workspace()?.downgrade();
16023        let (buffer, start) = self
16024            .buffer
16025            .read(cx)
16026            .text_anchor_for_position(rename.range.start, cx)?;
16027        let (end_buffer, _) = self
16028            .buffer
16029            .read(cx)
16030            .text_anchor_for_position(rename.range.end, cx)?;
16031        if buffer != end_buffer {
16032            return None;
16033        }
16034
16035        let old_name = rename.old_name;
16036        let new_name = rename.editor.read(cx).text(cx);
16037
16038        let rename = self.semantics_provider.as_ref()?.perform_rename(
16039            &buffer,
16040            start,
16041            new_name.clone(),
16042            cx,
16043        )?;
16044
16045        Some(cx.spawn_in(window, async move |editor, cx| {
16046            let project_transaction = rename.await?;
16047            Self::open_project_transaction(
16048                &editor,
16049                workspace,
16050                project_transaction,
16051                format!("Rename: {}{}", old_name, new_name),
16052                cx,
16053            )
16054            .await?;
16055
16056            editor.update(cx, |editor, cx| {
16057                editor.refresh_document_highlights(cx);
16058            })?;
16059            Ok(())
16060        }))
16061    }
16062
16063    fn take_rename(
16064        &mut self,
16065        moving_cursor: bool,
16066        window: &mut Window,
16067        cx: &mut Context<Self>,
16068    ) -> Option<RenameState> {
16069        let rename = self.pending_rename.take()?;
16070        if rename.editor.focus_handle(cx).is_focused(window) {
16071            window.focus(&self.focus_handle);
16072        }
16073
16074        self.remove_blocks(
16075            [rename.block_id].into_iter().collect(),
16076            Some(Autoscroll::fit()),
16077            cx,
16078        );
16079        self.clear_highlights::<Rename>(cx);
16080        self.show_local_selections = true;
16081
16082        if moving_cursor {
16083            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16084                editor.selections.newest::<usize>(cx).head()
16085            });
16086
16087            // Update the selection to match the position of the selection inside
16088            // the rename editor.
16089            let snapshot = self.buffer.read(cx).read(cx);
16090            let rename_range = rename.range.to_offset(&snapshot);
16091            let cursor_in_editor = snapshot
16092                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16093                .min(rename_range.end);
16094            drop(snapshot);
16095
16096            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16097                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16098            });
16099        } else {
16100            self.refresh_document_highlights(cx);
16101        }
16102
16103        Some(rename)
16104    }
16105
16106    pub fn pending_rename(&self) -> Option<&RenameState> {
16107        self.pending_rename.as_ref()
16108    }
16109
16110    fn format(
16111        &mut self,
16112        _: &Format,
16113        window: &mut Window,
16114        cx: &mut Context<Self>,
16115    ) -> Option<Task<Result<()>>> {
16116        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16117
16118        let project = match &self.project {
16119            Some(project) => project.clone(),
16120            None => return None,
16121        };
16122
16123        Some(self.perform_format(
16124            project,
16125            FormatTrigger::Manual,
16126            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16127            window,
16128            cx,
16129        ))
16130    }
16131
16132    fn format_selections(
16133        &mut self,
16134        _: &FormatSelections,
16135        window: &mut Window,
16136        cx: &mut Context<Self>,
16137    ) -> Option<Task<Result<()>>> {
16138        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16139
16140        let project = match &self.project {
16141            Some(project) => project.clone(),
16142            None => return None,
16143        };
16144
16145        let ranges = self
16146            .selections
16147            .all_adjusted(cx)
16148            .into_iter()
16149            .map(|selection| selection.range())
16150            .collect_vec();
16151
16152        Some(self.perform_format(
16153            project,
16154            FormatTrigger::Manual,
16155            FormatTarget::Ranges(ranges),
16156            window,
16157            cx,
16158        ))
16159    }
16160
16161    fn perform_format(
16162        &mut self,
16163        project: Entity<Project>,
16164        trigger: FormatTrigger,
16165        target: FormatTarget,
16166        window: &mut Window,
16167        cx: &mut Context<Self>,
16168    ) -> Task<Result<()>> {
16169        let buffer = self.buffer.clone();
16170        let (buffers, target) = match target {
16171            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16172            FormatTarget::Ranges(selection_ranges) => {
16173                let multi_buffer = buffer.read(cx);
16174                let snapshot = multi_buffer.read(cx);
16175                let mut buffers = HashSet::default();
16176                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16177                    BTreeMap::new();
16178                for selection_range in selection_ranges {
16179                    for (buffer, buffer_range, _) in
16180                        snapshot.range_to_buffer_ranges(selection_range)
16181                    {
16182                        let buffer_id = buffer.remote_id();
16183                        let start = buffer.anchor_before(buffer_range.start);
16184                        let end = buffer.anchor_after(buffer_range.end);
16185                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16186                        buffer_id_to_ranges
16187                            .entry(buffer_id)
16188                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16189                            .or_insert_with(|| vec![start..end]);
16190                    }
16191                }
16192                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16193            }
16194        };
16195
16196        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16197        let selections_prev = transaction_id_prev
16198            .and_then(|transaction_id_prev| {
16199                // default to selections as they were after the last edit, if we have them,
16200                // instead of how they are now.
16201                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16202                // will take you back to where you made the last edit, instead of staying where you scrolled
16203                self.selection_history
16204                    .transaction(transaction_id_prev)
16205                    .map(|t| t.0.clone())
16206            })
16207            .unwrap_or_else(|| {
16208                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16209                self.selections.disjoint_anchors()
16210            });
16211
16212        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16213        let format = project.update(cx, |project, cx| {
16214            project.format(buffers, target, true, trigger, cx)
16215        });
16216
16217        cx.spawn_in(window, async move |editor, cx| {
16218            let transaction = futures::select_biased! {
16219                transaction = format.log_err().fuse() => transaction,
16220                () = timeout => {
16221                    log::warn!("timed out waiting for formatting");
16222                    None
16223                }
16224            };
16225
16226            buffer
16227                .update(cx, |buffer, cx| {
16228                    if let Some(transaction) = transaction {
16229                        if !buffer.is_singleton() {
16230                            buffer.push_transaction(&transaction.0, cx);
16231                        }
16232                    }
16233                    cx.notify();
16234                })
16235                .ok();
16236
16237            if let Some(transaction_id_now) =
16238                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16239            {
16240                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16241                if has_new_transaction {
16242                    _ = editor.update(cx, |editor, _| {
16243                        editor
16244                            .selection_history
16245                            .insert_transaction(transaction_id_now, selections_prev);
16246                    });
16247                }
16248            }
16249
16250            Ok(())
16251        })
16252    }
16253
16254    fn organize_imports(
16255        &mut self,
16256        _: &OrganizeImports,
16257        window: &mut Window,
16258        cx: &mut Context<Self>,
16259    ) -> Option<Task<Result<()>>> {
16260        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16261        let project = match &self.project {
16262            Some(project) => project.clone(),
16263            None => return None,
16264        };
16265        Some(self.perform_code_action_kind(
16266            project,
16267            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16268            window,
16269            cx,
16270        ))
16271    }
16272
16273    fn perform_code_action_kind(
16274        &mut self,
16275        project: Entity<Project>,
16276        kind: CodeActionKind,
16277        window: &mut Window,
16278        cx: &mut Context<Self>,
16279    ) -> Task<Result<()>> {
16280        let buffer = self.buffer.clone();
16281        let buffers = buffer.read(cx).all_buffers();
16282        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16283        let apply_action = project.update(cx, |project, cx| {
16284            project.apply_code_action_kind(buffers, kind, true, cx)
16285        });
16286        cx.spawn_in(window, async move |_, cx| {
16287            let transaction = futures::select_biased! {
16288                () = timeout => {
16289                    log::warn!("timed out waiting for executing code action");
16290                    None
16291                }
16292                transaction = apply_action.log_err().fuse() => transaction,
16293            };
16294            buffer
16295                .update(cx, |buffer, cx| {
16296                    // check if we need this
16297                    if let Some(transaction) = transaction {
16298                        if !buffer.is_singleton() {
16299                            buffer.push_transaction(&transaction.0, cx);
16300                        }
16301                    }
16302                    cx.notify();
16303                })
16304                .ok();
16305            Ok(())
16306        })
16307    }
16308
16309    pub fn restart_language_server(
16310        &mut self,
16311        _: &RestartLanguageServer,
16312        _: &mut Window,
16313        cx: &mut Context<Self>,
16314    ) {
16315        if let Some(project) = self.project.clone() {
16316            self.buffer.update(cx, |multi_buffer, cx| {
16317                project.update(cx, |project, cx| {
16318                    project.restart_language_servers_for_buffers(
16319                        multi_buffer.all_buffers().into_iter().collect(),
16320                        HashSet::default(),
16321                        cx,
16322                    );
16323                });
16324            })
16325        }
16326    }
16327
16328    pub fn stop_language_server(
16329        &mut self,
16330        _: &StopLanguageServer,
16331        _: &mut Window,
16332        cx: &mut Context<Self>,
16333    ) {
16334        if let Some(project) = self.project.clone() {
16335            self.buffer.update(cx, |multi_buffer, cx| {
16336                project.update(cx, |project, cx| {
16337                    project.stop_language_servers_for_buffers(
16338                        multi_buffer.all_buffers().into_iter().collect(),
16339                        HashSet::default(),
16340                        cx,
16341                    );
16342                    cx.emit(project::Event::RefreshInlayHints);
16343                });
16344            });
16345        }
16346    }
16347
16348    fn cancel_language_server_work(
16349        workspace: &mut Workspace,
16350        _: &actions::CancelLanguageServerWork,
16351        _: &mut Window,
16352        cx: &mut Context<Workspace>,
16353    ) {
16354        let project = workspace.project();
16355        let buffers = workspace
16356            .active_item(cx)
16357            .and_then(|item| item.act_as::<Editor>(cx))
16358            .map_or(HashSet::default(), |editor| {
16359                editor.read(cx).buffer.read(cx).all_buffers()
16360            });
16361        project.update(cx, |project, cx| {
16362            project.cancel_language_server_work_for_buffers(buffers, cx);
16363        });
16364    }
16365
16366    fn show_character_palette(
16367        &mut self,
16368        _: &ShowCharacterPalette,
16369        window: &mut Window,
16370        _: &mut Context<Self>,
16371    ) {
16372        window.show_character_palette();
16373    }
16374
16375    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16376        if !self.diagnostics_enabled() {
16377            return;
16378        }
16379
16380        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16381            let buffer = self.buffer.read(cx).snapshot(cx);
16382            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16383            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16384            let is_valid = buffer
16385                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16386                .any(|entry| {
16387                    entry.diagnostic.is_primary
16388                        && !entry.range.is_empty()
16389                        && entry.range.start == primary_range_start
16390                        && entry.diagnostic.message == active_diagnostics.active_message
16391                });
16392
16393            if !is_valid {
16394                self.dismiss_diagnostics(cx);
16395            }
16396        }
16397    }
16398
16399    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16400        match &self.active_diagnostics {
16401            ActiveDiagnostic::Group(group) => Some(group),
16402            _ => None,
16403        }
16404    }
16405
16406    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16407        if !self.diagnostics_enabled() {
16408            return;
16409        }
16410        self.dismiss_diagnostics(cx);
16411        self.active_diagnostics = ActiveDiagnostic::All;
16412    }
16413
16414    fn activate_diagnostics(
16415        &mut self,
16416        buffer_id: BufferId,
16417        diagnostic: DiagnosticEntry<usize>,
16418        window: &mut Window,
16419        cx: &mut Context<Self>,
16420    ) {
16421        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16422            return;
16423        }
16424        self.dismiss_diagnostics(cx);
16425        let snapshot = self.snapshot(window, cx);
16426        let buffer = self.buffer.read(cx).snapshot(cx);
16427        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16428            return;
16429        };
16430
16431        let diagnostic_group = buffer
16432            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16433            .collect::<Vec<_>>();
16434
16435        let blocks =
16436            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16437
16438        let blocks = self.display_map.update(cx, |display_map, cx| {
16439            display_map.insert_blocks(blocks, cx).into_iter().collect()
16440        });
16441        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16442            active_range: buffer.anchor_before(diagnostic.range.start)
16443                ..buffer.anchor_after(diagnostic.range.end),
16444            active_message: diagnostic.diagnostic.message.clone(),
16445            group_id: diagnostic.diagnostic.group_id,
16446            blocks,
16447        });
16448        cx.notify();
16449    }
16450
16451    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16452        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16453            return;
16454        };
16455
16456        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16457        if let ActiveDiagnostic::Group(group) = prev {
16458            self.display_map.update(cx, |display_map, cx| {
16459                display_map.remove_blocks(group.blocks, cx);
16460            });
16461            cx.notify();
16462        }
16463    }
16464
16465    /// Disable inline diagnostics rendering for this editor.
16466    pub fn disable_inline_diagnostics(&mut self) {
16467        self.inline_diagnostics_enabled = false;
16468        self.inline_diagnostics_update = Task::ready(());
16469        self.inline_diagnostics.clear();
16470    }
16471
16472    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16473        self.diagnostics_enabled = false;
16474        self.dismiss_diagnostics(cx);
16475        self.inline_diagnostics_update = Task::ready(());
16476        self.inline_diagnostics.clear();
16477    }
16478
16479    pub fn diagnostics_enabled(&self) -> bool {
16480        self.diagnostics_enabled && self.mode.is_full()
16481    }
16482
16483    pub fn inline_diagnostics_enabled(&self) -> bool {
16484        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16485    }
16486
16487    pub fn show_inline_diagnostics(&self) -> bool {
16488        self.show_inline_diagnostics
16489    }
16490
16491    pub fn toggle_inline_diagnostics(
16492        &mut self,
16493        _: &ToggleInlineDiagnostics,
16494        window: &mut Window,
16495        cx: &mut Context<Editor>,
16496    ) {
16497        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16498        self.refresh_inline_diagnostics(false, window, cx);
16499    }
16500
16501    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16502        self.diagnostics_max_severity = severity;
16503        self.display_map.update(cx, |display_map, _| {
16504            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16505        });
16506    }
16507
16508    pub fn toggle_diagnostics(
16509        &mut self,
16510        _: &ToggleDiagnostics,
16511        window: &mut Window,
16512        cx: &mut Context<Editor>,
16513    ) {
16514        if !self.diagnostics_enabled() {
16515            return;
16516        }
16517
16518        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16519            EditorSettings::get_global(cx)
16520                .diagnostics_max_severity
16521                .filter(|severity| severity != &DiagnosticSeverity::Off)
16522                .unwrap_or(DiagnosticSeverity::Hint)
16523        } else {
16524            DiagnosticSeverity::Off
16525        };
16526        self.set_max_diagnostics_severity(new_severity, cx);
16527        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16528            self.active_diagnostics = ActiveDiagnostic::None;
16529            self.inline_diagnostics_update = Task::ready(());
16530            self.inline_diagnostics.clear();
16531        } else {
16532            self.refresh_inline_diagnostics(false, window, cx);
16533        }
16534
16535        cx.notify();
16536    }
16537
16538    pub fn toggle_minimap(
16539        &mut self,
16540        _: &ToggleMinimap,
16541        window: &mut Window,
16542        cx: &mut Context<Editor>,
16543    ) {
16544        if self.supports_minimap(cx) {
16545            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16546        }
16547    }
16548
16549    fn refresh_inline_diagnostics(
16550        &mut self,
16551        debounce: bool,
16552        window: &mut Window,
16553        cx: &mut Context<Self>,
16554    ) {
16555        let max_severity = ProjectSettings::get_global(cx)
16556            .diagnostics
16557            .inline
16558            .max_severity
16559            .unwrap_or(self.diagnostics_max_severity);
16560
16561        if !self.inline_diagnostics_enabled()
16562            || !self.show_inline_diagnostics
16563            || max_severity == DiagnosticSeverity::Off
16564        {
16565            self.inline_diagnostics_update = Task::ready(());
16566            self.inline_diagnostics.clear();
16567            return;
16568        }
16569
16570        let debounce_ms = ProjectSettings::get_global(cx)
16571            .diagnostics
16572            .inline
16573            .update_debounce_ms;
16574        let debounce = if debounce && debounce_ms > 0 {
16575            Some(Duration::from_millis(debounce_ms))
16576        } else {
16577            None
16578        };
16579        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16580            if let Some(debounce) = debounce {
16581                cx.background_executor().timer(debounce).await;
16582            }
16583            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16584                editor
16585                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16586                    .ok()
16587            }) else {
16588                return;
16589            };
16590
16591            let new_inline_diagnostics = cx
16592                .background_spawn(async move {
16593                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16594                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16595                        let message = diagnostic_entry
16596                            .diagnostic
16597                            .message
16598                            .split_once('\n')
16599                            .map(|(line, _)| line)
16600                            .map(SharedString::new)
16601                            .unwrap_or_else(|| {
16602                                SharedString::from(diagnostic_entry.diagnostic.message)
16603                            });
16604                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16605                        let (Ok(i) | Err(i)) = inline_diagnostics
16606                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16607                        inline_diagnostics.insert(
16608                            i,
16609                            (
16610                                start_anchor,
16611                                InlineDiagnostic {
16612                                    message,
16613                                    group_id: diagnostic_entry.diagnostic.group_id,
16614                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16615                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16616                                    severity: diagnostic_entry.diagnostic.severity,
16617                                },
16618                            ),
16619                        );
16620                    }
16621                    inline_diagnostics
16622                })
16623                .await;
16624
16625            editor
16626                .update(cx, |editor, cx| {
16627                    editor.inline_diagnostics = new_inline_diagnostics;
16628                    cx.notify();
16629                })
16630                .ok();
16631        });
16632    }
16633
16634    fn pull_diagnostics(
16635        &mut self,
16636        buffer_id: Option<BufferId>,
16637        window: &Window,
16638        cx: &mut Context<Self>,
16639    ) -> Option<()> {
16640        if !self.mode().is_full() {
16641            return None;
16642        }
16643        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16644            .diagnostics
16645            .lsp_pull_diagnostics;
16646        if !pull_diagnostics_settings.enabled {
16647            return None;
16648        }
16649        let project = self.project.as_ref()?.downgrade();
16650        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16651        let mut buffers = self.buffer.read(cx).all_buffers();
16652        if let Some(buffer_id) = buffer_id {
16653            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16654        }
16655
16656        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16657            cx.background_executor().timer(debounce).await;
16658
16659            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16660                buffers
16661                    .into_iter()
16662                    .filter_map(|buffer| {
16663                        project
16664                            .update(cx, |project, cx| {
16665                                project.lsp_store().update(cx, |lsp_store, cx| {
16666                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16667                                })
16668                            })
16669                            .ok()
16670                    })
16671                    .collect::<FuturesUnordered<_>>()
16672            }) else {
16673                return;
16674            };
16675
16676            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16677                match pull_task {
16678                    Ok(()) => {
16679                        if editor
16680                            .update_in(cx, |editor, window, cx| {
16681                                editor.update_diagnostics_state(window, cx);
16682                            })
16683                            .is_err()
16684                        {
16685                            return;
16686                        }
16687                    }
16688                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16689                }
16690            }
16691        });
16692
16693        Some(())
16694    }
16695
16696    pub fn set_selections_from_remote(
16697        &mut self,
16698        selections: Vec<Selection<Anchor>>,
16699        pending_selection: Option<Selection<Anchor>>,
16700        window: &mut Window,
16701        cx: &mut Context<Self>,
16702    ) {
16703        let old_cursor_position = self.selections.newest_anchor().head();
16704        self.selections.change_with(cx, |s| {
16705            s.select_anchors(selections);
16706            if let Some(pending_selection) = pending_selection {
16707                s.set_pending(pending_selection, SelectMode::Character);
16708            } else {
16709                s.clear_pending();
16710            }
16711        });
16712        self.selections_did_change(
16713            false,
16714            &old_cursor_position,
16715            SelectionEffects::default(),
16716            window,
16717            cx,
16718        );
16719    }
16720
16721    pub fn transact(
16722        &mut self,
16723        window: &mut Window,
16724        cx: &mut Context<Self>,
16725        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16726    ) -> Option<TransactionId> {
16727        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16728            this.start_transaction_at(Instant::now(), window, cx);
16729            update(this, window, cx);
16730            this.end_transaction_at(Instant::now(), cx)
16731        })
16732    }
16733
16734    pub fn start_transaction_at(
16735        &mut self,
16736        now: Instant,
16737        window: &mut Window,
16738        cx: &mut Context<Self>,
16739    ) {
16740        self.end_selection(window, cx);
16741        if let Some(tx_id) = self
16742            .buffer
16743            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16744        {
16745            self.selection_history
16746                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16747            cx.emit(EditorEvent::TransactionBegun {
16748                transaction_id: tx_id,
16749            })
16750        }
16751    }
16752
16753    pub fn end_transaction_at(
16754        &mut self,
16755        now: Instant,
16756        cx: &mut Context<Self>,
16757    ) -> Option<TransactionId> {
16758        if let Some(transaction_id) = self
16759            .buffer
16760            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16761        {
16762            if let Some((_, end_selections)) =
16763                self.selection_history.transaction_mut(transaction_id)
16764            {
16765                *end_selections = Some(self.selections.disjoint_anchors());
16766            } else {
16767                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16768            }
16769
16770            cx.emit(EditorEvent::Edited { transaction_id });
16771            Some(transaction_id)
16772        } else {
16773            None
16774        }
16775    }
16776
16777    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16778        if self.selection_mark_mode {
16779            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16780                s.move_with(|_, sel| {
16781                    sel.collapse_to(sel.head(), SelectionGoal::None);
16782                });
16783            })
16784        }
16785        self.selection_mark_mode = true;
16786        cx.notify();
16787    }
16788
16789    pub fn swap_selection_ends(
16790        &mut self,
16791        _: &actions::SwapSelectionEnds,
16792        window: &mut Window,
16793        cx: &mut Context<Self>,
16794    ) {
16795        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16796            s.move_with(|_, sel| {
16797                if sel.start != sel.end {
16798                    sel.reversed = !sel.reversed
16799                }
16800            });
16801        });
16802        self.request_autoscroll(Autoscroll::newest(), cx);
16803        cx.notify();
16804    }
16805
16806    pub fn toggle_fold(
16807        &mut self,
16808        _: &actions::ToggleFold,
16809        window: &mut Window,
16810        cx: &mut Context<Self>,
16811    ) {
16812        if self.is_singleton(cx) {
16813            let selection = self.selections.newest::<Point>(cx);
16814
16815            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16816            let range = if selection.is_empty() {
16817                let point = selection.head().to_display_point(&display_map);
16818                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16819                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16820                    .to_point(&display_map);
16821                start..end
16822            } else {
16823                selection.range()
16824            };
16825            if display_map.folds_in_range(range).next().is_some() {
16826                self.unfold_lines(&Default::default(), window, cx)
16827            } else {
16828                self.fold(&Default::default(), window, cx)
16829            }
16830        } else {
16831            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16832            let buffer_ids: HashSet<_> = self
16833                .selections
16834                .disjoint_anchor_ranges()
16835                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16836                .collect();
16837
16838            let should_unfold = buffer_ids
16839                .iter()
16840                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16841
16842            for buffer_id in buffer_ids {
16843                if should_unfold {
16844                    self.unfold_buffer(buffer_id, cx);
16845                } else {
16846                    self.fold_buffer(buffer_id, cx);
16847                }
16848            }
16849        }
16850    }
16851
16852    pub fn toggle_fold_recursive(
16853        &mut self,
16854        _: &actions::ToggleFoldRecursive,
16855        window: &mut Window,
16856        cx: &mut Context<Self>,
16857    ) {
16858        let selection = self.selections.newest::<Point>(cx);
16859
16860        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16861        let range = if selection.is_empty() {
16862            let point = selection.head().to_display_point(&display_map);
16863            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16864            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16865                .to_point(&display_map);
16866            start..end
16867        } else {
16868            selection.range()
16869        };
16870        if display_map.folds_in_range(range).next().is_some() {
16871            self.unfold_recursive(&Default::default(), window, cx)
16872        } else {
16873            self.fold_recursive(&Default::default(), window, cx)
16874        }
16875    }
16876
16877    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16878        if self.is_singleton(cx) {
16879            let mut to_fold = Vec::new();
16880            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16881            let selections = self.selections.all_adjusted(cx);
16882
16883            for selection in selections {
16884                let range = selection.range().sorted();
16885                let buffer_start_row = range.start.row;
16886
16887                if range.start.row != range.end.row {
16888                    let mut found = false;
16889                    let mut row = range.start.row;
16890                    while row <= range.end.row {
16891                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16892                        {
16893                            found = true;
16894                            row = crease.range().end.row + 1;
16895                            to_fold.push(crease);
16896                        } else {
16897                            row += 1
16898                        }
16899                    }
16900                    if found {
16901                        continue;
16902                    }
16903                }
16904
16905                for row in (0..=range.start.row).rev() {
16906                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16907                        if crease.range().end.row >= buffer_start_row {
16908                            to_fold.push(crease);
16909                            if row <= range.start.row {
16910                                break;
16911                            }
16912                        }
16913                    }
16914                }
16915            }
16916
16917            self.fold_creases(to_fold, true, window, cx);
16918        } else {
16919            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16920            let buffer_ids = self
16921                .selections
16922                .disjoint_anchor_ranges()
16923                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16924                .collect::<HashSet<_>>();
16925            for buffer_id in buffer_ids {
16926                self.fold_buffer(buffer_id, cx);
16927            }
16928        }
16929    }
16930
16931    fn fold_at_level(
16932        &mut self,
16933        fold_at: &FoldAtLevel,
16934        window: &mut Window,
16935        cx: &mut Context<Self>,
16936    ) {
16937        if !self.buffer.read(cx).is_singleton() {
16938            return;
16939        }
16940
16941        let fold_at_level = fold_at.0;
16942        let snapshot = self.buffer.read(cx).snapshot(cx);
16943        let mut to_fold = Vec::new();
16944        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16945
16946        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16947            while start_row < end_row {
16948                match self
16949                    .snapshot(window, cx)
16950                    .crease_for_buffer_row(MultiBufferRow(start_row))
16951                {
16952                    Some(crease) => {
16953                        let nested_start_row = crease.range().start.row + 1;
16954                        let nested_end_row = crease.range().end.row;
16955
16956                        if current_level < fold_at_level {
16957                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16958                        } else if current_level == fold_at_level {
16959                            to_fold.push(crease);
16960                        }
16961
16962                        start_row = nested_end_row + 1;
16963                    }
16964                    None => start_row += 1,
16965                }
16966            }
16967        }
16968
16969        self.fold_creases(to_fold, true, window, cx);
16970    }
16971
16972    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16973        if self.buffer.read(cx).is_singleton() {
16974            let mut fold_ranges = Vec::new();
16975            let snapshot = self.buffer.read(cx).snapshot(cx);
16976
16977            for row in 0..snapshot.max_row().0 {
16978                if let Some(foldable_range) = self
16979                    .snapshot(window, cx)
16980                    .crease_for_buffer_row(MultiBufferRow(row))
16981                {
16982                    fold_ranges.push(foldable_range);
16983                }
16984            }
16985
16986            self.fold_creases(fold_ranges, true, window, cx);
16987        } else {
16988            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16989                editor
16990                    .update_in(cx, |editor, _, cx| {
16991                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16992                            editor.fold_buffer(buffer_id, cx);
16993                        }
16994                    })
16995                    .ok();
16996            });
16997        }
16998    }
16999
17000    pub fn fold_function_bodies(
17001        &mut self,
17002        _: &actions::FoldFunctionBodies,
17003        window: &mut Window,
17004        cx: &mut Context<Self>,
17005    ) {
17006        let snapshot = self.buffer.read(cx).snapshot(cx);
17007
17008        let ranges = snapshot
17009            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17010            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17011            .collect::<Vec<_>>();
17012
17013        let creases = ranges
17014            .into_iter()
17015            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17016            .collect();
17017
17018        self.fold_creases(creases, true, window, cx);
17019    }
17020
17021    pub fn fold_recursive(
17022        &mut self,
17023        _: &actions::FoldRecursive,
17024        window: &mut Window,
17025        cx: &mut Context<Self>,
17026    ) {
17027        let mut to_fold = Vec::new();
17028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17029        let selections = self.selections.all_adjusted(cx);
17030
17031        for selection in selections {
17032            let range = selection.range().sorted();
17033            let buffer_start_row = range.start.row;
17034
17035            if range.start.row != range.end.row {
17036                let mut found = false;
17037                for row in range.start.row..=range.end.row {
17038                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17039                        found = true;
17040                        to_fold.push(crease);
17041                    }
17042                }
17043                if found {
17044                    continue;
17045                }
17046            }
17047
17048            for row in (0..=range.start.row).rev() {
17049                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17050                    if crease.range().end.row >= buffer_start_row {
17051                        to_fold.push(crease);
17052                    } else {
17053                        break;
17054                    }
17055                }
17056            }
17057        }
17058
17059        self.fold_creases(to_fold, true, window, cx);
17060    }
17061
17062    pub fn fold_at(
17063        &mut self,
17064        buffer_row: MultiBufferRow,
17065        window: &mut Window,
17066        cx: &mut Context<Self>,
17067    ) {
17068        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17069
17070        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17071            let autoscroll = self
17072                .selections
17073                .all::<Point>(cx)
17074                .iter()
17075                .any(|selection| crease.range().overlaps(&selection.range()));
17076
17077            self.fold_creases(vec![crease], autoscroll, window, cx);
17078        }
17079    }
17080
17081    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17082        if self.is_singleton(cx) {
17083            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17084            let buffer = &display_map.buffer_snapshot;
17085            let selections = self.selections.all::<Point>(cx);
17086            let ranges = selections
17087                .iter()
17088                .map(|s| {
17089                    let range = s.display_range(&display_map).sorted();
17090                    let mut start = range.start.to_point(&display_map);
17091                    let mut end = range.end.to_point(&display_map);
17092                    start.column = 0;
17093                    end.column = buffer.line_len(MultiBufferRow(end.row));
17094                    start..end
17095                })
17096                .collect::<Vec<_>>();
17097
17098            self.unfold_ranges(&ranges, true, true, cx);
17099        } else {
17100            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17101            let buffer_ids = self
17102                .selections
17103                .disjoint_anchor_ranges()
17104                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17105                .collect::<HashSet<_>>();
17106            for buffer_id in buffer_ids {
17107                self.unfold_buffer(buffer_id, cx);
17108            }
17109        }
17110    }
17111
17112    pub fn unfold_recursive(
17113        &mut self,
17114        _: &UnfoldRecursive,
17115        _window: &mut Window,
17116        cx: &mut Context<Self>,
17117    ) {
17118        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17119        let selections = self.selections.all::<Point>(cx);
17120        let ranges = selections
17121            .iter()
17122            .map(|s| {
17123                let mut range = s.display_range(&display_map).sorted();
17124                *range.start.column_mut() = 0;
17125                *range.end.column_mut() = display_map.line_len(range.end.row());
17126                let start = range.start.to_point(&display_map);
17127                let end = range.end.to_point(&display_map);
17128                start..end
17129            })
17130            .collect::<Vec<_>>();
17131
17132        self.unfold_ranges(&ranges, true, true, cx);
17133    }
17134
17135    pub fn unfold_at(
17136        &mut self,
17137        buffer_row: MultiBufferRow,
17138        _window: &mut Window,
17139        cx: &mut Context<Self>,
17140    ) {
17141        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17142
17143        let intersection_range = Point::new(buffer_row.0, 0)
17144            ..Point::new(
17145                buffer_row.0,
17146                display_map.buffer_snapshot.line_len(buffer_row),
17147            );
17148
17149        let autoscroll = self
17150            .selections
17151            .all::<Point>(cx)
17152            .iter()
17153            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17154
17155        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17156    }
17157
17158    pub fn unfold_all(
17159        &mut self,
17160        _: &actions::UnfoldAll,
17161        _window: &mut Window,
17162        cx: &mut Context<Self>,
17163    ) {
17164        if self.buffer.read(cx).is_singleton() {
17165            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17166            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17167        } else {
17168            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17169                editor
17170                    .update(cx, |editor, cx| {
17171                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17172                            editor.unfold_buffer(buffer_id, cx);
17173                        }
17174                    })
17175                    .ok();
17176            });
17177        }
17178    }
17179
17180    pub fn fold_selected_ranges(
17181        &mut self,
17182        _: &FoldSelectedRanges,
17183        window: &mut Window,
17184        cx: &mut Context<Self>,
17185    ) {
17186        let selections = self.selections.all_adjusted(cx);
17187        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17188        let ranges = selections
17189            .into_iter()
17190            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17191            .collect::<Vec<_>>();
17192        self.fold_creases(ranges, true, window, cx);
17193    }
17194
17195    pub fn fold_ranges<T: ToOffset + Clone>(
17196        &mut self,
17197        ranges: Vec<Range<T>>,
17198        auto_scroll: bool,
17199        window: &mut Window,
17200        cx: &mut Context<Self>,
17201    ) {
17202        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17203        let ranges = ranges
17204            .into_iter()
17205            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17206            .collect::<Vec<_>>();
17207        self.fold_creases(ranges, auto_scroll, window, cx);
17208    }
17209
17210    pub fn fold_creases<T: ToOffset + Clone>(
17211        &mut self,
17212        creases: Vec<Crease<T>>,
17213        auto_scroll: bool,
17214        _window: &mut Window,
17215        cx: &mut Context<Self>,
17216    ) {
17217        if creases.is_empty() {
17218            return;
17219        }
17220
17221        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17222
17223        if auto_scroll {
17224            self.request_autoscroll(Autoscroll::fit(), cx);
17225        }
17226
17227        cx.notify();
17228
17229        self.scrollbar_marker_state.dirty = true;
17230        self.folds_did_change(cx);
17231    }
17232
17233    /// Removes any folds whose ranges intersect any of the given ranges.
17234    pub fn unfold_ranges<T: ToOffset + Clone>(
17235        &mut self,
17236        ranges: &[Range<T>],
17237        inclusive: bool,
17238        auto_scroll: bool,
17239        cx: &mut Context<Self>,
17240    ) {
17241        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17242            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17243        });
17244        self.folds_did_change(cx);
17245    }
17246
17247    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17248        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17249            return;
17250        }
17251        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17252        self.display_map.update(cx, |display_map, cx| {
17253            display_map.fold_buffers([buffer_id], cx)
17254        });
17255        cx.emit(EditorEvent::BufferFoldToggled {
17256            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17257            folded: true,
17258        });
17259        cx.notify();
17260    }
17261
17262    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17263        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17264            return;
17265        }
17266        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17267        self.display_map.update(cx, |display_map, cx| {
17268            display_map.unfold_buffers([buffer_id], cx);
17269        });
17270        cx.emit(EditorEvent::BufferFoldToggled {
17271            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17272            folded: false,
17273        });
17274        cx.notify();
17275    }
17276
17277    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17278        self.display_map.read(cx).is_buffer_folded(buffer)
17279    }
17280
17281    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17282        self.display_map.read(cx).folded_buffers()
17283    }
17284
17285    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17286        self.display_map.update(cx, |display_map, cx| {
17287            display_map.disable_header_for_buffer(buffer_id, cx);
17288        });
17289        cx.notify();
17290    }
17291
17292    /// Removes any folds with the given ranges.
17293    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17294        &mut self,
17295        ranges: &[Range<T>],
17296        type_id: TypeId,
17297        auto_scroll: bool,
17298        cx: &mut Context<Self>,
17299    ) {
17300        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17301            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17302        });
17303        self.folds_did_change(cx);
17304    }
17305
17306    fn remove_folds_with<T: ToOffset + Clone>(
17307        &mut self,
17308        ranges: &[Range<T>],
17309        auto_scroll: bool,
17310        cx: &mut Context<Self>,
17311        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17312    ) {
17313        if ranges.is_empty() {
17314            return;
17315        }
17316
17317        let mut buffers_affected = HashSet::default();
17318        let multi_buffer = self.buffer().read(cx);
17319        for range in ranges {
17320            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17321                buffers_affected.insert(buffer.read(cx).remote_id());
17322            };
17323        }
17324
17325        self.display_map.update(cx, update);
17326
17327        if auto_scroll {
17328            self.request_autoscroll(Autoscroll::fit(), cx);
17329        }
17330
17331        cx.notify();
17332        self.scrollbar_marker_state.dirty = true;
17333        self.active_indent_guides_state.dirty = true;
17334    }
17335
17336    pub fn update_renderer_widths(
17337        &mut self,
17338        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17339        cx: &mut Context<Self>,
17340    ) -> bool {
17341        self.display_map
17342            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17343    }
17344
17345    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17346        self.display_map.read(cx).fold_placeholder.clone()
17347    }
17348
17349    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17350        self.buffer.update(cx, |buffer, cx| {
17351            buffer.set_all_diff_hunks_expanded(cx);
17352        });
17353    }
17354
17355    pub fn expand_all_diff_hunks(
17356        &mut self,
17357        _: &ExpandAllDiffHunks,
17358        _window: &mut Window,
17359        cx: &mut Context<Self>,
17360    ) {
17361        self.buffer.update(cx, |buffer, cx| {
17362            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17363        });
17364    }
17365
17366    pub fn toggle_selected_diff_hunks(
17367        &mut self,
17368        _: &ToggleSelectedDiffHunks,
17369        _window: &mut Window,
17370        cx: &mut Context<Self>,
17371    ) {
17372        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17373        self.toggle_diff_hunks_in_ranges(ranges, cx);
17374    }
17375
17376    pub fn diff_hunks_in_ranges<'a>(
17377        &'a self,
17378        ranges: &'a [Range<Anchor>],
17379        buffer: &'a MultiBufferSnapshot,
17380    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17381        ranges.iter().flat_map(move |range| {
17382            let end_excerpt_id = range.end.excerpt_id;
17383            let range = range.to_point(buffer);
17384            let mut peek_end = range.end;
17385            if range.end.row < buffer.max_row().0 {
17386                peek_end = Point::new(range.end.row + 1, 0);
17387            }
17388            buffer
17389                .diff_hunks_in_range(range.start..peek_end)
17390                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17391        })
17392    }
17393
17394    pub fn has_stageable_diff_hunks_in_ranges(
17395        &self,
17396        ranges: &[Range<Anchor>],
17397        snapshot: &MultiBufferSnapshot,
17398    ) -> bool {
17399        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17400        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17401    }
17402
17403    pub fn toggle_staged_selected_diff_hunks(
17404        &mut self,
17405        _: &::git::ToggleStaged,
17406        _: &mut Window,
17407        cx: &mut Context<Self>,
17408    ) {
17409        let snapshot = self.buffer.read(cx).snapshot(cx);
17410        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17411        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17412        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17413    }
17414
17415    pub fn set_render_diff_hunk_controls(
17416        &mut self,
17417        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17418        cx: &mut Context<Self>,
17419    ) {
17420        self.render_diff_hunk_controls = render_diff_hunk_controls;
17421        cx.notify();
17422    }
17423
17424    pub fn stage_and_next(
17425        &mut self,
17426        _: &::git::StageAndNext,
17427        window: &mut Window,
17428        cx: &mut Context<Self>,
17429    ) {
17430        self.do_stage_or_unstage_and_next(true, window, cx);
17431    }
17432
17433    pub fn unstage_and_next(
17434        &mut self,
17435        _: &::git::UnstageAndNext,
17436        window: &mut Window,
17437        cx: &mut Context<Self>,
17438    ) {
17439        self.do_stage_or_unstage_and_next(false, window, cx);
17440    }
17441
17442    pub fn stage_or_unstage_diff_hunks(
17443        &mut self,
17444        stage: bool,
17445        ranges: Vec<Range<Anchor>>,
17446        cx: &mut Context<Self>,
17447    ) {
17448        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17449        cx.spawn(async move |this, cx| {
17450            task.await?;
17451            this.update(cx, |this, cx| {
17452                let snapshot = this.buffer.read(cx).snapshot(cx);
17453                let chunk_by = this
17454                    .diff_hunks_in_ranges(&ranges, &snapshot)
17455                    .chunk_by(|hunk| hunk.buffer_id);
17456                for (buffer_id, hunks) in &chunk_by {
17457                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17458                }
17459            })
17460        })
17461        .detach_and_log_err(cx);
17462    }
17463
17464    fn save_buffers_for_ranges_if_needed(
17465        &mut self,
17466        ranges: &[Range<Anchor>],
17467        cx: &mut Context<Editor>,
17468    ) -> Task<Result<()>> {
17469        let multibuffer = self.buffer.read(cx);
17470        let snapshot = multibuffer.read(cx);
17471        let buffer_ids: HashSet<_> = ranges
17472            .iter()
17473            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17474            .collect();
17475        drop(snapshot);
17476
17477        let mut buffers = HashSet::default();
17478        for buffer_id in buffer_ids {
17479            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17480                let buffer = buffer_entity.read(cx);
17481                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17482                {
17483                    buffers.insert(buffer_entity);
17484                }
17485            }
17486        }
17487
17488        if let Some(project) = &self.project {
17489            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17490        } else {
17491            Task::ready(Ok(()))
17492        }
17493    }
17494
17495    fn do_stage_or_unstage_and_next(
17496        &mut self,
17497        stage: bool,
17498        window: &mut Window,
17499        cx: &mut Context<Self>,
17500    ) {
17501        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17502
17503        if ranges.iter().any(|range| range.start != range.end) {
17504            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17505            return;
17506        }
17507
17508        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17509        let snapshot = self.snapshot(window, cx);
17510        let position = self.selections.newest::<Point>(cx).head();
17511        let mut row = snapshot
17512            .buffer_snapshot
17513            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17514            .find(|hunk| hunk.row_range.start.0 > position.row)
17515            .map(|hunk| hunk.row_range.start);
17516
17517        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17518        // Outside of the project diff editor, wrap around to the beginning.
17519        if !all_diff_hunks_expanded {
17520            row = row.or_else(|| {
17521                snapshot
17522                    .buffer_snapshot
17523                    .diff_hunks_in_range(Point::zero()..position)
17524                    .find(|hunk| hunk.row_range.end.0 < position.row)
17525                    .map(|hunk| hunk.row_range.start)
17526            });
17527        }
17528
17529        if let Some(row) = row {
17530            let destination = Point::new(row.0, 0);
17531            let autoscroll = Autoscroll::center();
17532
17533            self.unfold_ranges(&[destination..destination], false, false, cx);
17534            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17535                s.select_ranges([destination..destination]);
17536            });
17537        }
17538    }
17539
17540    fn do_stage_or_unstage(
17541        &self,
17542        stage: bool,
17543        buffer_id: BufferId,
17544        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17545        cx: &mut App,
17546    ) -> Option<()> {
17547        let project = self.project.as_ref()?;
17548        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17549        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17550        let buffer_snapshot = buffer.read(cx).snapshot();
17551        let file_exists = buffer_snapshot
17552            .file()
17553            .is_some_and(|file| file.disk_state().exists());
17554        diff.update(cx, |diff, cx| {
17555            diff.stage_or_unstage_hunks(
17556                stage,
17557                &hunks
17558                    .map(|hunk| buffer_diff::DiffHunk {
17559                        buffer_range: hunk.buffer_range,
17560                        diff_base_byte_range: hunk.diff_base_byte_range,
17561                        secondary_status: hunk.secondary_status,
17562                        range: Point::zero()..Point::zero(), // unused
17563                    })
17564                    .collect::<Vec<_>>(),
17565                &buffer_snapshot,
17566                file_exists,
17567                cx,
17568            )
17569        });
17570        None
17571    }
17572
17573    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17574        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17575        self.buffer
17576            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17577    }
17578
17579    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17580        self.buffer.update(cx, |buffer, cx| {
17581            let ranges = vec![Anchor::min()..Anchor::max()];
17582            if !buffer.all_diff_hunks_expanded()
17583                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17584            {
17585                buffer.collapse_diff_hunks(ranges, cx);
17586                true
17587            } else {
17588                false
17589            }
17590        })
17591    }
17592
17593    fn toggle_diff_hunks_in_ranges(
17594        &mut self,
17595        ranges: Vec<Range<Anchor>>,
17596        cx: &mut Context<Editor>,
17597    ) {
17598        self.buffer.update(cx, |buffer, cx| {
17599            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17600            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17601        })
17602    }
17603
17604    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17605        self.buffer.update(cx, |buffer, cx| {
17606            let snapshot = buffer.snapshot(cx);
17607            let excerpt_id = range.end.excerpt_id;
17608            let point_range = range.to_point(&snapshot);
17609            let expand = !buffer.single_hunk_is_expanded(range, cx);
17610            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17611        })
17612    }
17613
17614    pub(crate) fn apply_all_diff_hunks(
17615        &mut self,
17616        _: &ApplyAllDiffHunks,
17617        window: &mut Window,
17618        cx: &mut Context<Self>,
17619    ) {
17620        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17621
17622        let buffers = self.buffer.read(cx).all_buffers();
17623        for branch_buffer in buffers {
17624            branch_buffer.update(cx, |branch_buffer, cx| {
17625                branch_buffer.merge_into_base(Vec::new(), cx);
17626            });
17627        }
17628
17629        if let Some(project) = self.project.clone() {
17630            self.save(
17631                SaveOptions {
17632                    format: true,
17633                    autosave: false,
17634                },
17635                project,
17636                window,
17637                cx,
17638            )
17639            .detach_and_log_err(cx);
17640        }
17641    }
17642
17643    pub(crate) fn apply_selected_diff_hunks(
17644        &mut self,
17645        _: &ApplyDiffHunk,
17646        window: &mut Window,
17647        cx: &mut Context<Self>,
17648    ) {
17649        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17650        let snapshot = self.snapshot(window, cx);
17651        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17652        let mut ranges_by_buffer = HashMap::default();
17653        self.transact(window, cx, |editor, _window, cx| {
17654            for hunk in hunks {
17655                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17656                    ranges_by_buffer
17657                        .entry(buffer.clone())
17658                        .or_insert_with(Vec::new)
17659                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17660                }
17661            }
17662
17663            for (buffer, ranges) in ranges_by_buffer {
17664                buffer.update(cx, |buffer, cx| {
17665                    buffer.merge_into_base(ranges, cx);
17666                });
17667            }
17668        });
17669
17670        if let Some(project) = self.project.clone() {
17671            self.save(
17672                SaveOptions {
17673                    format: true,
17674                    autosave: false,
17675                },
17676                project,
17677                window,
17678                cx,
17679            )
17680            .detach_and_log_err(cx);
17681        }
17682    }
17683
17684    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17685        if hovered != self.gutter_hovered {
17686            self.gutter_hovered = hovered;
17687            cx.notify();
17688        }
17689    }
17690
17691    pub fn insert_blocks(
17692        &mut self,
17693        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17694        autoscroll: Option<Autoscroll>,
17695        cx: &mut Context<Self>,
17696    ) -> Vec<CustomBlockId> {
17697        let blocks = self
17698            .display_map
17699            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17700        if let Some(autoscroll) = autoscroll {
17701            self.request_autoscroll(autoscroll, cx);
17702        }
17703        cx.notify();
17704        blocks
17705    }
17706
17707    pub fn resize_blocks(
17708        &mut self,
17709        heights: HashMap<CustomBlockId, u32>,
17710        autoscroll: Option<Autoscroll>,
17711        cx: &mut Context<Self>,
17712    ) {
17713        self.display_map
17714            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17715        if let Some(autoscroll) = autoscroll {
17716            self.request_autoscroll(autoscroll, cx);
17717        }
17718        cx.notify();
17719    }
17720
17721    pub fn replace_blocks(
17722        &mut self,
17723        renderers: HashMap<CustomBlockId, RenderBlock>,
17724        autoscroll: Option<Autoscroll>,
17725        cx: &mut Context<Self>,
17726    ) {
17727        self.display_map
17728            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17729        if let Some(autoscroll) = autoscroll {
17730            self.request_autoscroll(autoscroll, cx);
17731        }
17732        cx.notify();
17733    }
17734
17735    pub fn remove_blocks(
17736        &mut self,
17737        block_ids: HashSet<CustomBlockId>,
17738        autoscroll: Option<Autoscroll>,
17739        cx: &mut Context<Self>,
17740    ) {
17741        self.display_map.update(cx, |display_map, cx| {
17742            display_map.remove_blocks(block_ids, cx)
17743        });
17744        if let Some(autoscroll) = autoscroll {
17745            self.request_autoscroll(autoscroll, cx);
17746        }
17747        cx.notify();
17748    }
17749
17750    pub fn row_for_block(
17751        &self,
17752        block_id: CustomBlockId,
17753        cx: &mut Context<Self>,
17754    ) -> Option<DisplayRow> {
17755        self.display_map
17756            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17757    }
17758
17759    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17760        self.focused_block = Some(focused_block);
17761    }
17762
17763    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17764        self.focused_block.take()
17765    }
17766
17767    pub fn insert_creases(
17768        &mut self,
17769        creases: impl IntoIterator<Item = Crease<Anchor>>,
17770        cx: &mut Context<Self>,
17771    ) -> Vec<CreaseId> {
17772        self.display_map
17773            .update(cx, |map, cx| map.insert_creases(creases, cx))
17774    }
17775
17776    pub fn remove_creases(
17777        &mut self,
17778        ids: impl IntoIterator<Item = CreaseId>,
17779        cx: &mut Context<Self>,
17780    ) -> Vec<(CreaseId, Range<Anchor>)> {
17781        self.display_map
17782            .update(cx, |map, cx| map.remove_creases(ids, cx))
17783    }
17784
17785    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17786        self.display_map
17787            .update(cx, |map, cx| map.snapshot(cx))
17788            .longest_row()
17789    }
17790
17791    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17792        self.display_map
17793            .update(cx, |map, cx| map.snapshot(cx))
17794            .max_point()
17795    }
17796
17797    pub fn text(&self, cx: &App) -> String {
17798        self.buffer.read(cx).read(cx).text()
17799    }
17800
17801    pub fn is_empty(&self, cx: &App) -> bool {
17802        self.buffer.read(cx).read(cx).is_empty()
17803    }
17804
17805    pub fn text_option(&self, cx: &App) -> Option<String> {
17806        let text = self.text(cx);
17807        let text = text.trim();
17808
17809        if text.is_empty() {
17810            return None;
17811        }
17812
17813        Some(text.to_string())
17814    }
17815
17816    pub fn set_text(
17817        &mut self,
17818        text: impl Into<Arc<str>>,
17819        window: &mut Window,
17820        cx: &mut Context<Self>,
17821    ) {
17822        self.transact(window, cx, |this, _, cx| {
17823            this.buffer
17824                .read(cx)
17825                .as_singleton()
17826                .expect("you can only call set_text on editors for singleton buffers")
17827                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17828        });
17829    }
17830
17831    pub fn display_text(&self, cx: &mut App) -> String {
17832        self.display_map
17833            .update(cx, |map, cx| map.snapshot(cx))
17834            .text()
17835    }
17836
17837    fn create_minimap(
17838        &self,
17839        minimap_settings: MinimapSettings,
17840        window: &mut Window,
17841        cx: &mut Context<Self>,
17842    ) -> Option<Entity<Self>> {
17843        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17844            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17845    }
17846
17847    fn initialize_new_minimap(
17848        &self,
17849        minimap_settings: MinimapSettings,
17850        window: &mut Window,
17851        cx: &mut Context<Self>,
17852    ) -> Entity<Self> {
17853        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17854
17855        let mut minimap = Editor::new_internal(
17856            EditorMode::Minimap {
17857                parent: cx.weak_entity(),
17858            },
17859            self.buffer.clone(),
17860            self.project.clone(),
17861            Some(self.display_map.clone()),
17862            window,
17863            cx,
17864        );
17865        minimap.scroll_manager.clone_state(&self.scroll_manager);
17866        minimap.set_text_style_refinement(TextStyleRefinement {
17867            font_size: Some(MINIMAP_FONT_SIZE),
17868            font_weight: Some(MINIMAP_FONT_WEIGHT),
17869            ..Default::default()
17870        });
17871        minimap.update_minimap_configuration(minimap_settings, cx);
17872        cx.new(|_| minimap)
17873    }
17874
17875    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17876        let current_line_highlight = minimap_settings
17877            .current_line_highlight
17878            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17879        self.set_current_line_highlight(Some(current_line_highlight));
17880    }
17881
17882    pub fn minimap(&self) -> Option<&Entity<Self>> {
17883        self.minimap
17884            .as_ref()
17885            .filter(|_| self.minimap_visibility.visible())
17886    }
17887
17888    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17889        let mut wrap_guides = smallvec![];
17890
17891        if self.show_wrap_guides == Some(false) {
17892            return wrap_guides;
17893        }
17894
17895        let settings = self.buffer.read(cx).language_settings(cx);
17896        if settings.show_wrap_guides {
17897            match self.soft_wrap_mode(cx) {
17898                SoftWrap::Column(soft_wrap) => {
17899                    wrap_guides.push((soft_wrap as usize, true));
17900                }
17901                SoftWrap::Bounded(soft_wrap) => {
17902                    wrap_guides.push((soft_wrap as usize, true));
17903                }
17904                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17905            }
17906            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17907        }
17908
17909        wrap_guides
17910    }
17911
17912    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17913        let settings = self.buffer.read(cx).language_settings(cx);
17914        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17915        match mode {
17916            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17917                SoftWrap::None
17918            }
17919            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17920            language_settings::SoftWrap::PreferredLineLength => {
17921                SoftWrap::Column(settings.preferred_line_length)
17922            }
17923            language_settings::SoftWrap::Bounded => {
17924                SoftWrap::Bounded(settings.preferred_line_length)
17925            }
17926        }
17927    }
17928
17929    pub fn set_soft_wrap_mode(
17930        &mut self,
17931        mode: language_settings::SoftWrap,
17932
17933        cx: &mut Context<Self>,
17934    ) {
17935        self.soft_wrap_mode_override = Some(mode);
17936        cx.notify();
17937    }
17938
17939    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17940        self.hard_wrap = hard_wrap;
17941        cx.notify();
17942    }
17943
17944    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17945        self.text_style_refinement = Some(style);
17946    }
17947
17948    /// called by the Element so we know what style we were most recently rendered with.
17949    pub(crate) fn set_style(
17950        &mut self,
17951        style: EditorStyle,
17952        window: &mut Window,
17953        cx: &mut Context<Self>,
17954    ) {
17955        // We intentionally do not inform the display map about the minimap style
17956        // so that wrapping is not recalculated and stays consistent for the editor
17957        // and its linked minimap.
17958        if !self.mode.is_minimap() {
17959            let rem_size = window.rem_size();
17960            self.display_map.update(cx, |map, cx| {
17961                map.set_font(
17962                    style.text.font(),
17963                    style.text.font_size.to_pixels(rem_size),
17964                    cx,
17965                )
17966            });
17967        }
17968        self.style = Some(style);
17969    }
17970
17971    pub fn style(&self) -> Option<&EditorStyle> {
17972        self.style.as_ref()
17973    }
17974
17975    // Called by the element. This method is not designed to be called outside of the editor
17976    // element's layout code because it does not notify when rewrapping is computed synchronously.
17977    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17978        self.display_map
17979            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17980    }
17981
17982    pub fn set_soft_wrap(&mut self) {
17983        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17984    }
17985
17986    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17987        if self.soft_wrap_mode_override.is_some() {
17988            self.soft_wrap_mode_override.take();
17989        } else {
17990            let soft_wrap = match self.soft_wrap_mode(cx) {
17991                SoftWrap::GitDiff => return,
17992                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17993                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17994                    language_settings::SoftWrap::None
17995                }
17996            };
17997            self.soft_wrap_mode_override = Some(soft_wrap);
17998        }
17999        cx.notify();
18000    }
18001
18002    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18003        let Some(workspace) = self.workspace() else {
18004            return;
18005        };
18006        let fs = workspace.read(cx).app_state().fs.clone();
18007        let current_show = TabBarSettings::get_global(cx).show;
18008        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18009            setting.show = Some(!current_show);
18010        });
18011    }
18012
18013    pub fn toggle_indent_guides(
18014        &mut self,
18015        _: &ToggleIndentGuides,
18016        _: &mut Window,
18017        cx: &mut Context<Self>,
18018    ) {
18019        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18020            self.buffer
18021                .read(cx)
18022                .language_settings(cx)
18023                .indent_guides
18024                .enabled
18025        });
18026        self.show_indent_guides = Some(!currently_enabled);
18027        cx.notify();
18028    }
18029
18030    fn should_show_indent_guides(&self) -> Option<bool> {
18031        self.show_indent_guides
18032    }
18033
18034    pub fn toggle_line_numbers(
18035        &mut self,
18036        _: &ToggleLineNumbers,
18037        _: &mut Window,
18038        cx: &mut Context<Self>,
18039    ) {
18040        let mut editor_settings = EditorSettings::get_global(cx).clone();
18041        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18042        EditorSettings::override_global(editor_settings, cx);
18043    }
18044
18045    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18046        if let Some(show_line_numbers) = self.show_line_numbers {
18047            return show_line_numbers;
18048        }
18049        EditorSettings::get_global(cx).gutter.line_numbers
18050    }
18051
18052    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18053        self.use_relative_line_numbers
18054            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18055    }
18056
18057    pub fn toggle_relative_line_numbers(
18058        &mut self,
18059        _: &ToggleRelativeLineNumbers,
18060        _: &mut Window,
18061        cx: &mut Context<Self>,
18062    ) {
18063        let is_relative = self.should_use_relative_line_numbers(cx);
18064        self.set_relative_line_number(Some(!is_relative), cx)
18065    }
18066
18067    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18068        self.use_relative_line_numbers = is_relative;
18069        cx.notify();
18070    }
18071
18072    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18073        self.show_gutter = show_gutter;
18074        cx.notify();
18075    }
18076
18077    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18078        self.show_scrollbars = ScrollbarAxes {
18079            horizontal: show,
18080            vertical: show,
18081        };
18082        cx.notify();
18083    }
18084
18085    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18086        self.show_scrollbars.vertical = show;
18087        cx.notify();
18088    }
18089
18090    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18091        self.show_scrollbars.horizontal = show;
18092        cx.notify();
18093    }
18094
18095    pub fn set_minimap_visibility(
18096        &mut self,
18097        minimap_visibility: MinimapVisibility,
18098        window: &mut Window,
18099        cx: &mut Context<Self>,
18100    ) {
18101        if self.minimap_visibility != minimap_visibility {
18102            if minimap_visibility.visible() && self.minimap.is_none() {
18103                let minimap_settings = EditorSettings::get_global(cx).minimap;
18104                self.minimap =
18105                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18106            }
18107            self.minimap_visibility = minimap_visibility;
18108            cx.notify();
18109        }
18110    }
18111
18112    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18113        self.set_show_scrollbars(false, cx);
18114        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18115    }
18116
18117    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18118        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18119    }
18120
18121    /// Normally the text in full mode and auto height editors is padded on the
18122    /// left side by roughly half a character width for improved hit testing.
18123    ///
18124    /// Use this method to disable this for cases where this is not wanted (e.g.
18125    /// if you want to align the editor text with some other text above or below)
18126    /// or if you want to add this padding to single-line editors.
18127    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18128        self.offset_content = offset_content;
18129        cx.notify();
18130    }
18131
18132    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18133        self.show_line_numbers = Some(show_line_numbers);
18134        cx.notify();
18135    }
18136
18137    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18138        self.disable_expand_excerpt_buttons = true;
18139        cx.notify();
18140    }
18141
18142    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18143        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18144        cx.notify();
18145    }
18146
18147    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18148        self.show_code_actions = Some(show_code_actions);
18149        cx.notify();
18150    }
18151
18152    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18153        self.show_runnables = Some(show_runnables);
18154        cx.notify();
18155    }
18156
18157    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18158        self.show_breakpoints = Some(show_breakpoints);
18159        cx.notify();
18160    }
18161
18162    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18163        if self.display_map.read(cx).masked != masked {
18164            self.display_map.update(cx, |map, _| map.masked = masked);
18165        }
18166        cx.notify()
18167    }
18168
18169    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18170        self.show_wrap_guides = Some(show_wrap_guides);
18171        cx.notify();
18172    }
18173
18174    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18175        self.show_indent_guides = Some(show_indent_guides);
18176        cx.notify();
18177    }
18178
18179    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18180        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18181            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18182                if let Some(dir) = file.abs_path(cx).parent() {
18183                    return Some(dir.to_owned());
18184                }
18185            }
18186
18187            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18188                return Some(project_path.path.to_path_buf());
18189            }
18190        }
18191
18192        None
18193    }
18194
18195    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18196        self.active_excerpt(cx)?
18197            .1
18198            .read(cx)
18199            .file()
18200            .and_then(|f| f.as_local())
18201    }
18202
18203    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18204        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18205            let buffer = buffer.read(cx);
18206            if let Some(project_path) = buffer.project_path(cx) {
18207                let project = self.project.as_ref()?.read(cx);
18208                project.absolute_path(&project_path, cx)
18209            } else {
18210                buffer
18211                    .file()
18212                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18213            }
18214        })
18215    }
18216
18217    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18218        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18219            let project_path = buffer.read(cx).project_path(cx)?;
18220            let project = self.project.as_ref()?.read(cx);
18221            let entry = project.entry_for_path(&project_path, cx)?;
18222            let path = entry.path.to_path_buf();
18223            Some(path)
18224        })
18225    }
18226
18227    pub fn reveal_in_finder(
18228        &mut self,
18229        _: &RevealInFileManager,
18230        _window: &mut Window,
18231        cx: &mut Context<Self>,
18232    ) {
18233        if let Some(target) = self.target_file(cx) {
18234            cx.reveal_path(&target.abs_path(cx));
18235        }
18236    }
18237
18238    pub fn copy_path(
18239        &mut self,
18240        _: &zed_actions::workspace::CopyPath,
18241        _window: &mut Window,
18242        cx: &mut Context<Self>,
18243    ) {
18244        if let Some(path) = self.target_file_abs_path(cx) {
18245            if let Some(path) = path.to_str() {
18246                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18247            }
18248        }
18249    }
18250
18251    pub fn copy_relative_path(
18252        &mut self,
18253        _: &zed_actions::workspace::CopyRelativePath,
18254        _window: &mut Window,
18255        cx: &mut Context<Self>,
18256    ) {
18257        if let Some(path) = self.target_file_path(cx) {
18258            if let Some(path) = path.to_str() {
18259                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18260            }
18261        }
18262    }
18263
18264    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18265        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18266            buffer.read(cx).project_path(cx)
18267        } else {
18268            None
18269        }
18270    }
18271
18272    // Returns true if the editor handled a go-to-line request
18273    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18274        maybe!({
18275            let breakpoint_store = self.breakpoint_store.as_ref()?;
18276
18277            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18278            else {
18279                self.clear_row_highlights::<ActiveDebugLine>();
18280                return None;
18281            };
18282
18283            let position = active_stack_frame.position;
18284            let buffer_id = position.buffer_id?;
18285            let snapshot = self
18286                .project
18287                .as_ref()?
18288                .read(cx)
18289                .buffer_for_id(buffer_id, cx)?
18290                .read(cx)
18291                .snapshot();
18292
18293            let mut handled = false;
18294            for (id, ExcerptRange { context, .. }) in
18295                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18296            {
18297                if context.start.cmp(&position, &snapshot).is_ge()
18298                    || context.end.cmp(&position, &snapshot).is_lt()
18299                {
18300                    continue;
18301                }
18302                let snapshot = self.buffer.read(cx).snapshot(cx);
18303                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18304
18305                handled = true;
18306                self.clear_row_highlights::<ActiveDebugLine>();
18307
18308                self.go_to_line::<ActiveDebugLine>(
18309                    multibuffer_anchor,
18310                    Some(cx.theme().colors().editor_debugger_active_line_background),
18311                    window,
18312                    cx,
18313                );
18314
18315                cx.notify();
18316            }
18317
18318            handled.then_some(())
18319        })
18320        .is_some()
18321    }
18322
18323    pub fn copy_file_name_without_extension(
18324        &mut self,
18325        _: &CopyFileNameWithoutExtension,
18326        _: &mut Window,
18327        cx: &mut Context<Self>,
18328    ) {
18329        if let Some(file) = self.target_file(cx) {
18330            if let Some(file_stem) = file.path().file_stem() {
18331                if let Some(name) = file_stem.to_str() {
18332                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18333                }
18334            }
18335        }
18336    }
18337
18338    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18339        if let Some(file) = self.target_file(cx) {
18340            if let Some(file_name) = file.path().file_name() {
18341                if let Some(name) = file_name.to_str() {
18342                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18343                }
18344            }
18345        }
18346    }
18347
18348    pub fn toggle_git_blame(
18349        &mut self,
18350        _: &::git::Blame,
18351        window: &mut Window,
18352        cx: &mut Context<Self>,
18353    ) {
18354        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18355
18356        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18357            self.start_git_blame(true, window, cx);
18358        }
18359
18360        cx.notify();
18361    }
18362
18363    pub fn toggle_git_blame_inline(
18364        &mut self,
18365        _: &ToggleGitBlameInline,
18366        window: &mut Window,
18367        cx: &mut Context<Self>,
18368    ) {
18369        self.toggle_git_blame_inline_internal(true, window, cx);
18370        cx.notify();
18371    }
18372
18373    pub fn open_git_blame_commit(
18374        &mut self,
18375        _: &OpenGitBlameCommit,
18376        window: &mut Window,
18377        cx: &mut Context<Self>,
18378    ) {
18379        self.open_git_blame_commit_internal(window, cx);
18380    }
18381
18382    fn open_git_blame_commit_internal(
18383        &mut self,
18384        window: &mut Window,
18385        cx: &mut Context<Self>,
18386    ) -> Option<()> {
18387        let blame = self.blame.as_ref()?;
18388        let snapshot = self.snapshot(window, cx);
18389        let cursor = self.selections.newest::<Point>(cx).head();
18390        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18391        let blame_entry = blame
18392            .update(cx, |blame, cx| {
18393                blame
18394                    .blame_for_rows(
18395                        &[RowInfo {
18396                            buffer_id: Some(buffer.remote_id()),
18397                            buffer_row: Some(point.row),
18398                            ..Default::default()
18399                        }],
18400                        cx,
18401                    )
18402                    .next()
18403            })
18404            .flatten()?;
18405        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18406        let repo = blame.read(cx).repository(cx)?;
18407        let workspace = self.workspace()?.downgrade();
18408        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18409        None
18410    }
18411
18412    pub fn git_blame_inline_enabled(&self) -> bool {
18413        self.git_blame_inline_enabled
18414    }
18415
18416    pub fn toggle_selection_menu(
18417        &mut self,
18418        _: &ToggleSelectionMenu,
18419        _: &mut Window,
18420        cx: &mut Context<Self>,
18421    ) {
18422        self.show_selection_menu = self
18423            .show_selection_menu
18424            .map(|show_selections_menu| !show_selections_menu)
18425            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18426
18427        cx.notify();
18428    }
18429
18430    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18431        self.show_selection_menu
18432            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18433    }
18434
18435    fn start_git_blame(
18436        &mut self,
18437        user_triggered: bool,
18438        window: &mut Window,
18439        cx: &mut Context<Self>,
18440    ) {
18441        if let Some(project) = self.project.as_ref() {
18442            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18443                return;
18444            };
18445
18446            if buffer.read(cx).file().is_none() {
18447                return;
18448            }
18449
18450            let focused = self.focus_handle(cx).contains_focused(window, cx);
18451
18452            let project = project.clone();
18453            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18454            self.blame_subscription =
18455                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18456            self.blame = Some(blame);
18457        }
18458    }
18459
18460    fn toggle_git_blame_inline_internal(
18461        &mut self,
18462        user_triggered: bool,
18463        window: &mut Window,
18464        cx: &mut Context<Self>,
18465    ) {
18466        if self.git_blame_inline_enabled {
18467            self.git_blame_inline_enabled = false;
18468            self.show_git_blame_inline = false;
18469            self.show_git_blame_inline_delay_task.take();
18470        } else {
18471            self.git_blame_inline_enabled = true;
18472            self.start_git_blame_inline(user_triggered, window, cx);
18473        }
18474
18475        cx.notify();
18476    }
18477
18478    fn start_git_blame_inline(
18479        &mut self,
18480        user_triggered: bool,
18481        window: &mut Window,
18482        cx: &mut Context<Self>,
18483    ) {
18484        self.start_git_blame(user_triggered, window, cx);
18485
18486        if ProjectSettings::get_global(cx)
18487            .git
18488            .inline_blame_delay()
18489            .is_some()
18490        {
18491            self.start_inline_blame_timer(window, cx);
18492        } else {
18493            self.show_git_blame_inline = true
18494        }
18495    }
18496
18497    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18498        self.blame.as_ref()
18499    }
18500
18501    pub fn show_git_blame_gutter(&self) -> bool {
18502        self.show_git_blame_gutter
18503    }
18504
18505    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18506        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18507    }
18508
18509    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18510        self.show_git_blame_inline
18511            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18512            && !self.newest_selection_head_on_empty_line(cx)
18513            && self.has_blame_entries(cx)
18514    }
18515
18516    fn has_blame_entries(&self, cx: &App) -> bool {
18517        self.blame()
18518            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18519    }
18520
18521    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18522        let cursor_anchor = self.selections.newest_anchor().head();
18523
18524        let snapshot = self.buffer.read(cx).snapshot(cx);
18525        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18526
18527        snapshot.line_len(buffer_row) == 0
18528    }
18529
18530    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18531        let buffer_and_selection = maybe!({
18532            let selection = self.selections.newest::<Point>(cx);
18533            let selection_range = selection.range();
18534
18535            let multi_buffer = self.buffer().read(cx);
18536            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18537            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18538
18539            let (buffer, range, _) = if selection.reversed {
18540                buffer_ranges.first()
18541            } else {
18542                buffer_ranges.last()
18543            }?;
18544
18545            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18546                ..text::ToPoint::to_point(&range.end, &buffer).row;
18547            Some((
18548                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18549                selection,
18550            ))
18551        });
18552
18553        let Some((buffer, selection)) = buffer_and_selection else {
18554            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18555        };
18556
18557        let Some(project) = self.project.as_ref() else {
18558            return Task::ready(Err(anyhow!("editor does not have project")));
18559        };
18560
18561        project.update(cx, |project, cx| {
18562            project.get_permalink_to_line(&buffer, selection, cx)
18563        })
18564    }
18565
18566    pub fn copy_permalink_to_line(
18567        &mut self,
18568        _: &CopyPermalinkToLine,
18569        window: &mut Window,
18570        cx: &mut Context<Self>,
18571    ) {
18572        let permalink_task = self.get_permalink_to_line(cx);
18573        let workspace = self.workspace();
18574
18575        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18576            Ok(permalink) => {
18577                cx.update(|_, cx| {
18578                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18579                })
18580                .ok();
18581            }
18582            Err(err) => {
18583                let message = format!("Failed to copy permalink: {err}");
18584
18585                anyhow::Result::<()>::Err(err).log_err();
18586
18587                if let Some(workspace) = workspace {
18588                    workspace
18589                        .update_in(cx, |workspace, _, cx| {
18590                            struct CopyPermalinkToLine;
18591
18592                            workspace.show_toast(
18593                                Toast::new(
18594                                    NotificationId::unique::<CopyPermalinkToLine>(),
18595                                    message,
18596                                ),
18597                                cx,
18598                            )
18599                        })
18600                        .ok();
18601                }
18602            }
18603        })
18604        .detach();
18605    }
18606
18607    pub fn copy_file_location(
18608        &mut self,
18609        _: &CopyFileLocation,
18610        _: &mut Window,
18611        cx: &mut Context<Self>,
18612    ) {
18613        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18614        if let Some(file) = self.target_file(cx) {
18615            if let Some(path) = file.path().to_str() {
18616                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18617            }
18618        }
18619    }
18620
18621    pub fn open_permalink_to_line(
18622        &mut self,
18623        _: &OpenPermalinkToLine,
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.open_url(permalink.as_ref());
18634                })
18635                .ok();
18636            }
18637            Err(err) => {
18638                let message = format!("Failed to open permalink: {err}");
18639
18640                anyhow::Result::<()>::Err(err).log_err();
18641
18642                if let Some(workspace) = workspace {
18643                    workspace
18644                        .update(cx, |workspace, cx| {
18645                            struct OpenPermalinkToLine;
18646
18647                            workspace.show_toast(
18648                                Toast::new(
18649                                    NotificationId::unique::<OpenPermalinkToLine>(),
18650                                    message,
18651                                ),
18652                                cx,
18653                            )
18654                        })
18655                        .ok();
18656                }
18657            }
18658        })
18659        .detach();
18660    }
18661
18662    pub fn insert_uuid_v4(
18663        &mut self,
18664        _: &InsertUuidV4,
18665        window: &mut Window,
18666        cx: &mut Context<Self>,
18667    ) {
18668        self.insert_uuid(UuidVersion::V4, window, cx);
18669    }
18670
18671    pub fn insert_uuid_v7(
18672        &mut self,
18673        _: &InsertUuidV7,
18674        window: &mut Window,
18675        cx: &mut Context<Self>,
18676    ) {
18677        self.insert_uuid(UuidVersion::V7, window, cx);
18678    }
18679
18680    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18681        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18682        self.transact(window, cx, |this, window, cx| {
18683            let edits = this
18684                .selections
18685                .all::<Point>(cx)
18686                .into_iter()
18687                .map(|selection| {
18688                    let uuid = match version {
18689                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18690                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18691                    };
18692
18693                    (selection.range(), uuid.to_string())
18694                });
18695            this.edit(edits, cx);
18696            this.refresh_inline_completion(true, false, window, cx);
18697        });
18698    }
18699
18700    pub fn open_selections_in_multibuffer(
18701        &mut self,
18702        _: &OpenSelectionsInMultibuffer,
18703        window: &mut Window,
18704        cx: &mut Context<Self>,
18705    ) {
18706        let multibuffer = self.buffer.read(cx);
18707
18708        let Some(buffer) = multibuffer.as_singleton() else {
18709            return;
18710        };
18711
18712        let Some(workspace) = self.workspace() else {
18713            return;
18714        };
18715
18716        let title = multibuffer.title(cx).to_string();
18717
18718        let locations = self
18719            .selections
18720            .all_anchors(cx)
18721            .into_iter()
18722            .map(|selection| Location {
18723                buffer: buffer.clone(),
18724                range: selection.start.text_anchor..selection.end.text_anchor,
18725            })
18726            .collect::<Vec<_>>();
18727
18728        cx.spawn_in(window, async move |_, cx| {
18729            workspace.update_in(cx, |workspace, window, cx| {
18730                Self::open_locations_in_multibuffer(
18731                    workspace,
18732                    locations,
18733                    format!("Selections for '{title}'"),
18734                    false,
18735                    MultibufferSelectionMode::All,
18736                    window,
18737                    cx,
18738                );
18739            })
18740        })
18741        .detach();
18742    }
18743
18744    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18745    /// last highlight added will be used.
18746    ///
18747    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18748    pub fn highlight_rows<T: 'static>(
18749        &mut self,
18750        range: Range<Anchor>,
18751        color: Hsla,
18752        options: RowHighlightOptions,
18753        cx: &mut Context<Self>,
18754    ) {
18755        let snapshot = self.buffer().read(cx).snapshot(cx);
18756        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18757        let ix = row_highlights.binary_search_by(|highlight| {
18758            Ordering::Equal
18759                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18760                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18761        });
18762
18763        if let Err(mut ix) = ix {
18764            let index = post_inc(&mut self.highlight_order);
18765
18766            // If this range intersects with the preceding highlight, then merge it with
18767            // the preceding highlight. Otherwise insert a new highlight.
18768            let mut merged = false;
18769            if ix > 0 {
18770                let prev_highlight = &mut row_highlights[ix - 1];
18771                if prev_highlight
18772                    .range
18773                    .end
18774                    .cmp(&range.start, &snapshot)
18775                    .is_ge()
18776                {
18777                    ix -= 1;
18778                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18779                        prev_highlight.range.end = range.end;
18780                    }
18781                    merged = true;
18782                    prev_highlight.index = index;
18783                    prev_highlight.color = color;
18784                    prev_highlight.options = options;
18785                }
18786            }
18787
18788            if !merged {
18789                row_highlights.insert(
18790                    ix,
18791                    RowHighlight {
18792                        range: range.clone(),
18793                        index,
18794                        color,
18795                        options,
18796                        type_id: TypeId::of::<T>(),
18797                    },
18798                );
18799            }
18800
18801            // If any of the following highlights intersect with this one, merge them.
18802            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18803                let highlight = &row_highlights[ix];
18804                if next_highlight
18805                    .range
18806                    .start
18807                    .cmp(&highlight.range.end, &snapshot)
18808                    .is_le()
18809                {
18810                    if next_highlight
18811                        .range
18812                        .end
18813                        .cmp(&highlight.range.end, &snapshot)
18814                        .is_gt()
18815                    {
18816                        row_highlights[ix].range.end = next_highlight.range.end;
18817                    }
18818                    row_highlights.remove(ix + 1);
18819                } else {
18820                    break;
18821                }
18822            }
18823        }
18824    }
18825
18826    /// Remove any highlighted row ranges of the given type that intersect the
18827    /// given ranges.
18828    pub fn remove_highlighted_rows<T: 'static>(
18829        &mut self,
18830        ranges_to_remove: Vec<Range<Anchor>>,
18831        cx: &mut Context<Self>,
18832    ) {
18833        let snapshot = self.buffer().read(cx).snapshot(cx);
18834        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18835        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18836        row_highlights.retain(|highlight| {
18837            while let Some(range_to_remove) = ranges_to_remove.peek() {
18838                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18839                    Ordering::Less | Ordering::Equal => {
18840                        ranges_to_remove.next();
18841                    }
18842                    Ordering::Greater => {
18843                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18844                            Ordering::Less | Ordering::Equal => {
18845                                return false;
18846                            }
18847                            Ordering::Greater => break,
18848                        }
18849                    }
18850                }
18851            }
18852
18853            true
18854        })
18855    }
18856
18857    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18858    pub fn clear_row_highlights<T: 'static>(&mut self) {
18859        self.highlighted_rows.remove(&TypeId::of::<T>());
18860    }
18861
18862    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18863    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18864        self.highlighted_rows
18865            .get(&TypeId::of::<T>())
18866            .map_or(&[] as &[_], |vec| vec.as_slice())
18867            .iter()
18868            .map(|highlight| (highlight.range.clone(), highlight.color))
18869    }
18870
18871    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18872    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18873    /// Allows to ignore certain kinds of highlights.
18874    pub fn highlighted_display_rows(
18875        &self,
18876        window: &mut Window,
18877        cx: &mut App,
18878    ) -> BTreeMap<DisplayRow, LineHighlight> {
18879        let snapshot = self.snapshot(window, cx);
18880        let mut used_highlight_orders = HashMap::default();
18881        self.highlighted_rows
18882            .iter()
18883            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18884            .fold(
18885                BTreeMap::<DisplayRow, LineHighlight>::new(),
18886                |mut unique_rows, highlight| {
18887                    let start = highlight.range.start.to_display_point(&snapshot);
18888                    let end = highlight.range.end.to_display_point(&snapshot);
18889                    let start_row = start.row().0;
18890                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18891                        && end.column() == 0
18892                    {
18893                        end.row().0.saturating_sub(1)
18894                    } else {
18895                        end.row().0
18896                    };
18897                    for row in start_row..=end_row {
18898                        let used_index =
18899                            used_highlight_orders.entry(row).or_insert(highlight.index);
18900                        if highlight.index >= *used_index {
18901                            *used_index = highlight.index;
18902                            unique_rows.insert(
18903                                DisplayRow(row),
18904                                LineHighlight {
18905                                    include_gutter: highlight.options.include_gutter,
18906                                    border: None,
18907                                    background: highlight.color.into(),
18908                                    type_id: Some(highlight.type_id),
18909                                },
18910                            );
18911                        }
18912                    }
18913                    unique_rows
18914                },
18915            )
18916    }
18917
18918    pub fn highlighted_display_row_for_autoscroll(
18919        &self,
18920        snapshot: &DisplaySnapshot,
18921    ) -> Option<DisplayRow> {
18922        self.highlighted_rows
18923            .values()
18924            .flat_map(|highlighted_rows| highlighted_rows.iter())
18925            .filter_map(|highlight| {
18926                if highlight.options.autoscroll {
18927                    Some(highlight.range.start.to_display_point(snapshot).row())
18928                } else {
18929                    None
18930                }
18931            })
18932            .min()
18933    }
18934
18935    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18936        self.highlight_background::<SearchWithinRange>(
18937            ranges,
18938            |colors| colors.colors().editor_document_highlight_read_background,
18939            cx,
18940        )
18941    }
18942
18943    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18944        self.breadcrumb_header = Some(new_header);
18945    }
18946
18947    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18948        self.clear_background_highlights::<SearchWithinRange>(cx);
18949    }
18950
18951    pub fn highlight_background<T: 'static>(
18952        &mut self,
18953        ranges: &[Range<Anchor>],
18954        color_fetcher: fn(&Theme) -> Hsla,
18955        cx: &mut Context<Self>,
18956    ) {
18957        self.background_highlights.insert(
18958            HighlightKey::Type(TypeId::of::<T>()),
18959            (color_fetcher, Arc::from(ranges)),
18960        );
18961        self.scrollbar_marker_state.dirty = true;
18962        cx.notify();
18963    }
18964
18965    pub fn highlight_background_key<T: 'static>(
18966        &mut self,
18967        key: usize,
18968        ranges: &[Range<Anchor>],
18969        color_fetcher: fn(&Theme) -> Hsla,
18970        cx: &mut Context<Self>,
18971    ) {
18972        self.background_highlights.insert(
18973            HighlightKey::TypePlus(TypeId::of::<T>(), key),
18974            (color_fetcher, Arc::from(ranges)),
18975        );
18976        self.scrollbar_marker_state.dirty = true;
18977        cx.notify();
18978    }
18979
18980    pub fn clear_background_highlights<T: 'static>(
18981        &mut self,
18982        cx: &mut Context<Self>,
18983    ) -> Option<BackgroundHighlight> {
18984        let text_highlights = self
18985            .background_highlights
18986            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
18987        if !text_highlights.1.is_empty() {
18988            self.scrollbar_marker_state.dirty = true;
18989            cx.notify();
18990        }
18991        Some(text_highlights)
18992    }
18993
18994    pub fn highlight_gutter<T: 'static>(
18995        &mut self,
18996        ranges: impl Into<Vec<Range<Anchor>>>,
18997        color_fetcher: fn(&App) -> Hsla,
18998        cx: &mut Context<Self>,
18999    ) {
19000        self.gutter_highlights
19001            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19002        cx.notify();
19003    }
19004
19005    pub fn clear_gutter_highlights<T: 'static>(
19006        &mut self,
19007        cx: &mut Context<Self>,
19008    ) -> Option<GutterHighlight> {
19009        cx.notify();
19010        self.gutter_highlights.remove(&TypeId::of::<T>())
19011    }
19012
19013    pub fn insert_gutter_highlight<T: 'static>(
19014        &mut self,
19015        range: Range<Anchor>,
19016        color_fetcher: fn(&App) -> Hsla,
19017        cx: &mut Context<Self>,
19018    ) {
19019        let snapshot = self.buffer().read(cx).snapshot(cx);
19020        let mut highlights = self
19021            .gutter_highlights
19022            .remove(&TypeId::of::<T>())
19023            .map(|(_, highlights)| highlights)
19024            .unwrap_or_default();
19025        let ix = highlights.binary_search_by(|highlight| {
19026            Ordering::Equal
19027                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19028                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19029        });
19030        if let Err(ix) = ix {
19031            highlights.insert(ix, range);
19032        }
19033        self.gutter_highlights
19034            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19035    }
19036
19037    pub fn remove_gutter_highlights<T: 'static>(
19038        &mut self,
19039        ranges_to_remove: Vec<Range<Anchor>>,
19040        cx: &mut Context<Self>,
19041    ) {
19042        let snapshot = self.buffer().read(cx).snapshot(cx);
19043        let Some((color_fetcher, mut gutter_highlights)) =
19044            self.gutter_highlights.remove(&TypeId::of::<T>())
19045        else {
19046            return;
19047        };
19048        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19049        gutter_highlights.retain(|highlight| {
19050            while let Some(range_to_remove) = ranges_to_remove.peek() {
19051                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19052                    Ordering::Less | Ordering::Equal => {
19053                        ranges_to_remove.next();
19054                    }
19055                    Ordering::Greater => {
19056                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19057                            Ordering::Less | Ordering::Equal => {
19058                                return false;
19059                            }
19060                            Ordering::Greater => break,
19061                        }
19062                    }
19063                }
19064            }
19065
19066            true
19067        });
19068        self.gutter_highlights
19069            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19070    }
19071
19072    #[cfg(feature = "test-support")]
19073    pub fn all_text_highlights(
19074        &self,
19075        window: &mut Window,
19076        cx: &mut Context<Self>,
19077    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19078        let snapshot = self.snapshot(window, cx);
19079        self.display_map.update(cx, |display_map, _| {
19080            display_map
19081                .all_text_highlights()
19082                .map(|highlight| {
19083                    let (style, ranges) = highlight.as_ref();
19084                    (
19085                        *style,
19086                        ranges
19087                            .iter()
19088                            .map(|range| range.clone().to_display_points(&snapshot))
19089                            .collect(),
19090                    )
19091                })
19092                .collect()
19093        })
19094    }
19095
19096    #[cfg(feature = "test-support")]
19097    pub fn all_text_background_highlights(
19098        &self,
19099        window: &mut Window,
19100        cx: &mut Context<Self>,
19101    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19102        let snapshot = self.snapshot(window, cx);
19103        let buffer = &snapshot.buffer_snapshot;
19104        let start = buffer.anchor_before(0);
19105        let end = buffer.anchor_after(buffer.len());
19106        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19107    }
19108
19109    #[cfg(feature = "test-support")]
19110    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19111        let snapshot = self.buffer().read(cx).snapshot(cx);
19112
19113        let highlights = self
19114            .background_highlights
19115            .get(&HighlightKey::Type(TypeId::of::<
19116                items::BufferSearchHighlights,
19117            >()));
19118
19119        if let Some((_color, ranges)) = highlights {
19120            ranges
19121                .iter()
19122                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19123                .collect_vec()
19124        } else {
19125            vec![]
19126        }
19127    }
19128
19129    fn document_highlights_for_position<'a>(
19130        &'a self,
19131        position: Anchor,
19132        buffer: &'a MultiBufferSnapshot,
19133    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19134        let read_highlights = self
19135            .background_highlights
19136            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19137            .map(|h| &h.1);
19138        let write_highlights = self
19139            .background_highlights
19140            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19141            .map(|h| &h.1);
19142        let left_position = position.bias_left(buffer);
19143        let right_position = position.bias_right(buffer);
19144        read_highlights
19145            .into_iter()
19146            .chain(write_highlights)
19147            .flat_map(move |ranges| {
19148                let start_ix = match ranges.binary_search_by(|probe| {
19149                    let cmp = probe.end.cmp(&left_position, buffer);
19150                    if cmp.is_ge() {
19151                        Ordering::Greater
19152                    } else {
19153                        Ordering::Less
19154                    }
19155                }) {
19156                    Ok(i) | Err(i) => i,
19157                };
19158
19159                ranges[start_ix..]
19160                    .iter()
19161                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19162            })
19163    }
19164
19165    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19166        self.background_highlights
19167            .get(&HighlightKey::Type(TypeId::of::<T>()))
19168            .map_or(false, |(_, highlights)| !highlights.is_empty())
19169    }
19170
19171    pub fn background_highlights_in_range(
19172        &self,
19173        search_range: Range<Anchor>,
19174        display_snapshot: &DisplaySnapshot,
19175        theme: &Theme,
19176    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19177        let mut results = Vec::new();
19178        for (color_fetcher, ranges) in self.background_highlights.values() {
19179            let color = color_fetcher(theme);
19180            let start_ix = match ranges.binary_search_by(|probe| {
19181                let cmp = probe
19182                    .end
19183                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19184                if cmp.is_gt() {
19185                    Ordering::Greater
19186                } else {
19187                    Ordering::Less
19188                }
19189            }) {
19190                Ok(i) | Err(i) => i,
19191            };
19192            for range in &ranges[start_ix..] {
19193                if range
19194                    .start
19195                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19196                    .is_ge()
19197                {
19198                    break;
19199                }
19200
19201                let start = range.start.to_display_point(display_snapshot);
19202                let end = range.end.to_display_point(display_snapshot);
19203                results.push((start..end, color))
19204            }
19205        }
19206        results
19207    }
19208
19209    pub fn background_highlight_row_ranges<T: 'static>(
19210        &self,
19211        search_range: Range<Anchor>,
19212        display_snapshot: &DisplaySnapshot,
19213        count: usize,
19214    ) -> Vec<RangeInclusive<DisplayPoint>> {
19215        let mut results = Vec::new();
19216        let Some((_, ranges)) = self
19217            .background_highlights
19218            .get(&HighlightKey::Type(TypeId::of::<T>()))
19219        else {
19220            return vec![];
19221        };
19222
19223        let start_ix = match ranges.binary_search_by(|probe| {
19224            let cmp = probe
19225                .end
19226                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19227            if cmp.is_gt() {
19228                Ordering::Greater
19229            } else {
19230                Ordering::Less
19231            }
19232        }) {
19233            Ok(i) | Err(i) => i,
19234        };
19235        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19236            if let (Some(start_display), Some(end_display)) = (start, end) {
19237                results.push(
19238                    start_display.to_display_point(display_snapshot)
19239                        ..=end_display.to_display_point(display_snapshot),
19240                );
19241            }
19242        };
19243        let mut start_row: Option<Point> = None;
19244        let mut end_row: Option<Point> = None;
19245        if ranges.len() > count {
19246            return Vec::new();
19247        }
19248        for range in &ranges[start_ix..] {
19249            if range
19250                .start
19251                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19252                .is_ge()
19253            {
19254                break;
19255            }
19256            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19257            if let Some(current_row) = &end_row {
19258                if end.row == current_row.row {
19259                    continue;
19260                }
19261            }
19262            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19263            if start_row.is_none() {
19264                assert_eq!(end_row, None);
19265                start_row = Some(start);
19266                end_row = Some(end);
19267                continue;
19268            }
19269            if let Some(current_end) = end_row.as_mut() {
19270                if start.row > current_end.row + 1 {
19271                    push_region(start_row, end_row);
19272                    start_row = Some(start);
19273                    end_row = Some(end);
19274                } else {
19275                    // Merge two hunks.
19276                    *current_end = end;
19277                }
19278            } else {
19279                unreachable!();
19280            }
19281        }
19282        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19283        push_region(start_row, end_row);
19284        results
19285    }
19286
19287    pub fn gutter_highlights_in_range(
19288        &self,
19289        search_range: Range<Anchor>,
19290        display_snapshot: &DisplaySnapshot,
19291        cx: &App,
19292    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19293        let mut results = Vec::new();
19294        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19295            let color = color_fetcher(cx);
19296            let start_ix = match ranges.binary_search_by(|probe| {
19297                let cmp = probe
19298                    .end
19299                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19300                if cmp.is_gt() {
19301                    Ordering::Greater
19302                } else {
19303                    Ordering::Less
19304                }
19305            }) {
19306                Ok(i) | Err(i) => i,
19307            };
19308            for range in &ranges[start_ix..] {
19309                if range
19310                    .start
19311                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19312                    .is_ge()
19313                {
19314                    break;
19315                }
19316
19317                let start = range.start.to_display_point(display_snapshot);
19318                let end = range.end.to_display_point(display_snapshot);
19319                results.push((start..end, color))
19320            }
19321        }
19322        results
19323    }
19324
19325    /// Get the text ranges corresponding to the redaction query
19326    pub fn redacted_ranges(
19327        &self,
19328        search_range: Range<Anchor>,
19329        display_snapshot: &DisplaySnapshot,
19330        cx: &App,
19331    ) -> Vec<Range<DisplayPoint>> {
19332        display_snapshot
19333            .buffer_snapshot
19334            .redacted_ranges(search_range, |file| {
19335                if let Some(file) = file {
19336                    file.is_private()
19337                        && EditorSettings::get(
19338                            Some(SettingsLocation {
19339                                worktree_id: file.worktree_id(cx),
19340                                path: file.path().as_ref(),
19341                            }),
19342                            cx,
19343                        )
19344                        .redact_private_values
19345                } else {
19346                    false
19347                }
19348            })
19349            .map(|range| {
19350                range.start.to_display_point(display_snapshot)
19351                    ..range.end.to_display_point(display_snapshot)
19352            })
19353            .collect()
19354    }
19355
19356    pub fn highlight_text_key<T: 'static>(
19357        &mut self,
19358        key: usize,
19359        ranges: Vec<Range<Anchor>>,
19360        style: HighlightStyle,
19361        cx: &mut Context<Self>,
19362    ) {
19363        self.display_map.update(cx, |map, _| {
19364            map.highlight_text(
19365                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19366                ranges,
19367                style,
19368            );
19369        });
19370        cx.notify();
19371    }
19372
19373    pub fn highlight_text<T: 'static>(
19374        &mut self,
19375        ranges: Vec<Range<Anchor>>,
19376        style: HighlightStyle,
19377        cx: &mut Context<Self>,
19378    ) {
19379        self.display_map.update(cx, |map, _| {
19380            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19381        });
19382        cx.notify();
19383    }
19384
19385    pub(crate) fn highlight_inlays<T: 'static>(
19386        &mut self,
19387        highlights: Vec<InlayHighlight>,
19388        style: HighlightStyle,
19389        cx: &mut Context<Self>,
19390    ) {
19391        self.display_map.update(cx, |map, _| {
19392            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19393        });
19394        cx.notify();
19395    }
19396
19397    pub fn text_highlights<'a, T: 'static>(
19398        &'a self,
19399        cx: &'a App,
19400    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19401        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19402    }
19403
19404    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19405        let cleared = self
19406            .display_map
19407            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19408        if cleared {
19409            cx.notify();
19410        }
19411    }
19412
19413    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19414        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19415            && self.focus_handle.is_focused(window)
19416    }
19417
19418    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19419        self.show_cursor_when_unfocused = is_enabled;
19420        cx.notify();
19421    }
19422
19423    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19424        cx.notify();
19425    }
19426
19427    fn on_debug_session_event(
19428        &mut self,
19429        _session: Entity<Session>,
19430        event: &SessionEvent,
19431        cx: &mut Context<Self>,
19432    ) {
19433        match event {
19434            SessionEvent::InvalidateInlineValue => {
19435                self.refresh_inline_values(cx);
19436            }
19437            _ => {}
19438        }
19439    }
19440
19441    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19442        let Some(project) = self.project.clone() else {
19443            return;
19444        };
19445
19446        if !self.inline_value_cache.enabled {
19447            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19448            self.splice_inlays(&inlays, Vec::new(), cx);
19449            return;
19450        }
19451
19452        let current_execution_position = self
19453            .highlighted_rows
19454            .get(&TypeId::of::<ActiveDebugLine>())
19455            .and_then(|lines| lines.last().map(|line| line.range.end));
19456
19457        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19458            let inline_values = editor
19459                .update(cx, |editor, cx| {
19460                    let Some(current_execution_position) = current_execution_position else {
19461                        return Some(Task::ready(Ok(Vec::new())));
19462                    };
19463
19464                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19465                        let snapshot = buffer.snapshot(cx);
19466
19467                        let excerpt = snapshot.excerpt_containing(
19468                            current_execution_position..current_execution_position,
19469                        )?;
19470
19471                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19472                    })?;
19473
19474                    let range =
19475                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19476
19477                    project.inline_values(buffer, range, cx)
19478                })
19479                .ok()
19480                .flatten()?
19481                .await
19482                .context("refreshing debugger inlays")
19483                .log_err()?;
19484
19485            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19486
19487            for (buffer_id, inline_value) in inline_values
19488                .into_iter()
19489                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19490            {
19491                buffer_inline_values
19492                    .entry(buffer_id)
19493                    .or_default()
19494                    .push(inline_value);
19495            }
19496
19497            editor
19498                .update(cx, |editor, cx| {
19499                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19500                    let mut new_inlays = Vec::default();
19501
19502                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19503                        let buffer_id = buffer_snapshot.remote_id();
19504                        buffer_inline_values
19505                            .get(&buffer_id)
19506                            .into_iter()
19507                            .flatten()
19508                            .for_each(|hint| {
19509                                let inlay = Inlay::debugger(
19510                                    post_inc(&mut editor.next_inlay_id),
19511                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19512                                    hint.text(),
19513                                );
19514
19515                                new_inlays.push(inlay);
19516                            });
19517                    }
19518
19519                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19520                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19521
19522                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19523                })
19524                .ok()?;
19525            Some(())
19526        });
19527    }
19528
19529    fn on_buffer_event(
19530        &mut self,
19531        multibuffer: &Entity<MultiBuffer>,
19532        event: &multi_buffer::Event,
19533        window: &mut Window,
19534        cx: &mut Context<Self>,
19535    ) {
19536        match event {
19537            multi_buffer::Event::Edited {
19538                singleton_buffer_edited,
19539                edited_buffer,
19540            } => {
19541                self.scrollbar_marker_state.dirty = true;
19542                self.active_indent_guides_state.dirty = true;
19543                self.refresh_active_diagnostics(cx);
19544                self.refresh_code_actions(window, cx);
19545                self.refresh_selected_text_highlights(true, window, cx);
19546                self.refresh_single_line_folds(window, cx);
19547                refresh_matching_bracket_highlights(self, window, cx);
19548                if self.has_active_inline_completion() {
19549                    self.update_visible_inline_completion(window, cx);
19550                }
19551                if let Some(project) = self.project.as_ref() {
19552                    if let Some(edited_buffer) = edited_buffer {
19553                        project.update(cx, |project, cx| {
19554                            self.registered_buffers
19555                                .entry(edited_buffer.read(cx).remote_id())
19556                                .or_insert_with(|| {
19557                                    project
19558                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19559                                });
19560                        });
19561                    }
19562                }
19563                cx.emit(EditorEvent::BufferEdited);
19564                cx.emit(SearchEvent::MatchesInvalidated);
19565
19566                if let Some(buffer) = edited_buffer {
19567                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19568                }
19569
19570                if *singleton_buffer_edited {
19571                    if let Some(buffer) = edited_buffer {
19572                        if buffer.read(cx).file().is_none() {
19573                            cx.emit(EditorEvent::TitleChanged);
19574                        }
19575                    }
19576                    if let Some(project) = &self.project {
19577                        #[allow(clippy::mutable_key_type)]
19578                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19579                            multibuffer
19580                                .all_buffers()
19581                                .into_iter()
19582                                .filter_map(|buffer| {
19583                                    buffer.update(cx, |buffer, cx| {
19584                                        let language = buffer.language()?;
19585                                        let should_discard = project.update(cx, |project, cx| {
19586                                            project.is_local()
19587                                                && !project.has_language_servers_for(buffer, cx)
19588                                        });
19589                                        should_discard.not().then_some(language.clone())
19590                                    })
19591                                })
19592                                .collect::<HashSet<_>>()
19593                        });
19594                        if !languages_affected.is_empty() {
19595                            self.refresh_inlay_hints(
19596                                InlayHintRefreshReason::BufferEdited(languages_affected),
19597                                cx,
19598                            );
19599                        }
19600                    }
19601                }
19602
19603                let Some(project) = &self.project else { return };
19604                let (telemetry, is_via_ssh) = {
19605                    let project = project.read(cx);
19606                    let telemetry = project.client().telemetry().clone();
19607                    let is_via_ssh = project.is_via_ssh();
19608                    (telemetry, is_via_ssh)
19609                };
19610                refresh_linked_ranges(self, window, cx);
19611                telemetry.log_edit_event("editor", is_via_ssh);
19612            }
19613            multi_buffer::Event::ExcerptsAdded {
19614                buffer,
19615                predecessor,
19616                excerpts,
19617            } => {
19618                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19619                let buffer_id = buffer.read(cx).remote_id();
19620                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19621                    if let Some(project) = &self.project {
19622                        update_uncommitted_diff_for_buffer(
19623                            cx.entity(),
19624                            project,
19625                            [buffer.clone()],
19626                            self.buffer.clone(),
19627                            cx,
19628                        )
19629                        .detach();
19630                    }
19631                }
19632                self.update_lsp_data(false, Some(buffer_id), window, cx);
19633                cx.emit(EditorEvent::ExcerptsAdded {
19634                    buffer: buffer.clone(),
19635                    predecessor: *predecessor,
19636                    excerpts: excerpts.clone(),
19637                });
19638                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19639            }
19640            multi_buffer::Event::ExcerptsRemoved {
19641                ids,
19642                removed_buffer_ids,
19643            } => {
19644                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19645                let buffer = self.buffer.read(cx);
19646                self.registered_buffers
19647                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19648                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19649                cx.emit(EditorEvent::ExcerptsRemoved {
19650                    ids: ids.clone(),
19651                    removed_buffer_ids: removed_buffer_ids.clone(),
19652                });
19653            }
19654            multi_buffer::Event::ExcerptsEdited {
19655                excerpt_ids,
19656                buffer_ids,
19657            } => {
19658                self.display_map.update(cx, |map, cx| {
19659                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19660                });
19661                cx.emit(EditorEvent::ExcerptsEdited {
19662                    ids: excerpt_ids.clone(),
19663                });
19664            }
19665            multi_buffer::Event::ExcerptsExpanded { ids } => {
19666                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19667                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19668            }
19669            multi_buffer::Event::Reparsed(buffer_id) => {
19670                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19671                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19672
19673                cx.emit(EditorEvent::Reparsed(*buffer_id));
19674            }
19675            multi_buffer::Event::DiffHunksToggled => {
19676                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19677            }
19678            multi_buffer::Event::LanguageChanged(buffer_id) => {
19679                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19680                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19681                cx.emit(EditorEvent::Reparsed(*buffer_id));
19682                cx.notify();
19683            }
19684            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19685            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19686            multi_buffer::Event::FileHandleChanged
19687            | multi_buffer::Event::Reloaded
19688            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19689            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19690            multi_buffer::Event::DiagnosticsUpdated => {
19691                self.update_diagnostics_state(window, cx);
19692            }
19693            _ => {}
19694        };
19695    }
19696
19697    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19698        if !self.diagnostics_enabled() {
19699            return;
19700        }
19701        self.refresh_active_diagnostics(cx);
19702        self.refresh_inline_diagnostics(true, window, cx);
19703        self.scrollbar_marker_state.dirty = true;
19704        cx.notify();
19705    }
19706
19707    pub fn start_temporary_diff_override(&mut self) {
19708        self.load_diff_task.take();
19709        self.temporary_diff_override = true;
19710    }
19711
19712    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19713        self.temporary_diff_override = false;
19714        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19715        self.buffer.update(cx, |buffer, cx| {
19716            buffer.set_all_diff_hunks_collapsed(cx);
19717        });
19718
19719        if let Some(project) = self.project.clone() {
19720            self.load_diff_task = Some(
19721                update_uncommitted_diff_for_buffer(
19722                    cx.entity(),
19723                    &project,
19724                    self.buffer.read(cx).all_buffers(),
19725                    self.buffer.clone(),
19726                    cx,
19727                )
19728                .shared(),
19729            );
19730        }
19731    }
19732
19733    fn on_display_map_changed(
19734        &mut self,
19735        _: Entity<DisplayMap>,
19736        _: &mut Window,
19737        cx: &mut Context<Self>,
19738    ) {
19739        cx.notify();
19740    }
19741
19742    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19743        let new_severity = if self.diagnostics_enabled() {
19744            EditorSettings::get_global(cx)
19745                .diagnostics_max_severity
19746                .unwrap_or(DiagnosticSeverity::Hint)
19747        } else {
19748            DiagnosticSeverity::Off
19749        };
19750        self.set_max_diagnostics_severity(new_severity, cx);
19751        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19752        self.update_edit_prediction_settings(cx);
19753        self.refresh_inline_completion(true, false, window, cx);
19754        self.refresh_inlay_hints(
19755            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19756                self.selections.newest_anchor().head(),
19757                &self.buffer.read(cx).snapshot(cx),
19758                cx,
19759            )),
19760            cx,
19761        );
19762
19763        let old_cursor_shape = self.cursor_shape;
19764
19765        {
19766            let editor_settings = EditorSettings::get_global(cx);
19767            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19768            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19769            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19770            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19771            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19772        }
19773
19774        if old_cursor_shape != self.cursor_shape {
19775            cx.emit(EditorEvent::CursorShapeChanged);
19776        }
19777
19778        let project_settings = ProjectSettings::get_global(cx);
19779        self.serialize_dirty_buffers =
19780            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19781
19782        if self.mode.is_full() {
19783            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19784            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19785            if self.show_inline_diagnostics != show_inline_diagnostics {
19786                self.show_inline_diagnostics = show_inline_diagnostics;
19787                self.refresh_inline_diagnostics(false, window, cx);
19788            }
19789
19790            if self.git_blame_inline_enabled != inline_blame_enabled {
19791                self.toggle_git_blame_inline_internal(false, window, cx);
19792            }
19793
19794            let minimap_settings = EditorSettings::get_global(cx).minimap;
19795            if self.minimap_visibility != MinimapVisibility::Disabled {
19796                if self.minimap_visibility.settings_visibility()
19797                    != minimap_settings.minimap_enabled()
19798                {
19799                    self.set_minimap_visibility(
19800                        MinimapVisibility::for_mode(self.mode(), cx),
19801                        window,
19802                        cx,
19803                    );
19804                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19805                    minimap_entity.update(cx, |minimap_editor, cx| {
19806                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19807                    })
19808                }
19809            }
19810        }
19811
19812        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19813            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19814        }) {
19815            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19816                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19817            }
19818            self.refresh_colors(false, None, window, cx);
19819        }
19820
19821        cx.notify();
19822    }
19823
19824    pub fn set_searchable(&mut self, searchable: bool) {
19825        self.searchable = searchable;
19826    }
19827
19828    pub fn searchable(&self) -> bool {
19829        self.searchable
19830    }
19831
19832    fn open_proposed_changes_editor(
19833        &mut self,
19834        _: &OpenProposedChangesEditor,
19835        window: &mut Window,
19836        cx: &mut Context<Self>,
19837    ) {
19838        let Some(workspace) = self.workspace() else {
19839            cx.propagate();
19840            return;
19841        };
19842
19843        let selections = self.selections.all::<usize>(cx);
19844        let multi_buffer = self.buffer.read(cx);
19845        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19846        let mut new_selections_by_buffer = HashMap::default();
19847        for selection in selections {
19848            for (buffer, range, _) in
19849                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19850            {
19851                let mut range = range.to_point(buffer);
19852                range.start.column = 0;
19853                range.end.column = buffer.line_len(range.end.row);
19854                new_selections_by_buffer
19855                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19856                    .or_insert(Vec::new())
19857                    .push(range)
19858            }
19859        }
19860
19861        let proposed_changes_buffers = new_selections_by_buffer
19862            .into_iter()
19863            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19864            .collect::<Vec<_>>();
19865        let proposed_changes_editor = cx.new(|cx| {
19866            ProposedChangesEditor::new(
19867                "Proposed changes",
19868                proposed_changes_buffers,
19869                self.project.clone(),
19870                window,
19871                cx,
19872            )
19873        });
19874
19875        window.defer(cx, move |window, cx| {
19876            workspace.update(cx, |workspace, cx| {
19877                workspace.active_pane().update(cx, |pane, cx| {
19878                    pane.add_item(
19879                        Box::new(proposed_changes_editor),
19880                        true,
19881                        true,
19882                        None,
19883                        window,
19884                        cx,
19885                    );
19886                });
19887            });
19888        });
19889    }
19890
19891    pub fn open_excerpts_in_split(
19892        &mut self,
19893        _: &OpenExcerptsSplit,
19894        window: &mut Window,
19895        cx: &mut Context<Self>,
19896    ) {
19897        self.open_excerpts_common(None, true, window, cx)
19898    }
19899
19900    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19901        self.open_excerpts_common(None, false, window, cx)
19902    }
19903
19904    fn open_excerpts_common(
19905        &mut self,
19906        jump_data: Option<JumpData>,
19907        split: bool,
19908        window: &mut Window,
19909        cx: &mut Context<Self>,
19910    ) {
19911        let Some(workspace) = self.workspace() else {
19912            cx.propagate();
19913            return;
19914        };
19915
19916        if self.buffer.read(cx).is_singleton() {
19917            cx.propagate();
19918            return;
19919        }
19920
19921        let mut new_selections_by_buffer = HashMap::default();
19922        match &jump_data {
19923            Some(JumpData::MultiBufferPoint {
19924                excerpt_id,
19925                position,
19926                anchor,
19927                line_offset_from_top,
19928            }) => {
19929                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19930                if let Some(buffer) = multi_buffer_snapshot
19931                    .buffer_id_for_excerpt(*excerpt_id)
19932                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19933                {
19934                    let buffer_snapshot = buffer.read(cx).snapshot();
19935                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19936                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19937                    } else {
19938                        buffer_snapshot.clip_point(*position, Bias::Left)
19939                    };
19940                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19941                    new_selections_by_buffer.insert(
19942                        buffer,
19943                        (
19944                            vec![jump_to_offset..jump_to_offset],
19945                            Some(*line_offset_from_top),
19946                        ),
19947                    );
19948                }
19949            }
19950            Some(JumpData::MultiBufferRow {
19951                row,
19952                line_offset_from_top,
19953            }) => {
19954                let point = MultiBufferPoint::new(row.0, 0);
19955                if let Some((buffer, buffer_point, _)) =
19956                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19957                {
19958                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19959                    new_selections_by_buffer
19960                        .entry(buffer)
19961                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19962                        .0
19963                        .push(buffer_offset..buffer_offset)
19964                }
19965            }
19966            None => {
19967                let selections = self.selections.all::<usize>(cx);
19968                let multi_buffer = self.buffer.read(cx);
19969                for selection in selections {
19970                    for (snapshot, range, _, anchor) in multi_buffer
19971                        .snapshot(cx)
19972                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19973                    {
19974                        if let Some(anchor) = anchor {
19975                            // selection is in a deleted hunk
19976                            let Some(buffer_id) = anchor.buffer_id else {
19977                                continue;
19978                            };
19979                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19980                                continue;
19981                            };
19982                            let offset = text::ToOffset::to_offset(
19983                                &anchor.text_anchor,
19984                                &buffer_handle.read(cx).snapshot(),
19985                            );
19986                            let range = offset..offset;
19987                            new_selections_by_buffer
19988                                .entry(buffer_handle)
19989                                .or_insert((Vec::new(), None))
19990                                .0
19991                                .push(range)
19992                        } else {
19993                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19994                            else {
19995                                continue;
19996                            };
19997                            new_selections_by_buffer
19998                                .entry(buffer_handle)
19999                                .or_insert((Vec::new(), None))
20000                                .0
20001                                .push(range)
20002                        }
20003                    }
20004                }
20005            }
20006        }
20007
20008        new_selections_by_buffer
20009            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20010
20011        if new_selections_by_buffer.is_empty() {
20012            return;
20013        }
20014
20015        // We defer the pane interaction because we ourselves are a workspace item
20016        // and activating a new item causes the pane to call a method on us reentrantly,
20017        // which panics if we're on the stack.
20018        window.defer(cx, move |window, cx| {
20019            workspace.update(cx, |workspace, cx| {
20020                let pane = if split {
20021                    workspace.adjacent_pane(window, cx)
20022                } else {
20023                    workspace.active_pane().clone()
20024                };
20025
20026                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20027                    let editor = buffer
20028                        .read(cx)
20029                        .file()
20030                        .is_none()
20031                        .then(|| {
20032                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20033                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20034                            // Instead, we try to activate the existing editor in the pane first.
20035                            let (editor, pane_item_index) =
20036                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20037                                    let editor = item.downcast::<Editor>()?;
20038                                    let singleton_buffer =
20039                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20040                                    if singleton_buffer == buffer {
20041                                        Some((editor, i))
20042                                    } else {
20043                                        None
20044                                    }
20045                                })?;
20046                            pane.update(cx, |pane, cx| {
20047                                pane.activate_item(pane_item_index, true, true, window, cx)
20048                            });
20049                            Some(editor)
20050                        })
20051                        .flatten()
20052                        .unwrap_or_else(|| {
20053                            workspace.open_project_item::<Self>(
20054                                pane.clone(),
20055                                buffer,
20056                                true,
20057                                true,
20058                                window,
20059                                cx,
20060                            )
20061                        });
20062
20063                    editor.update(cx, |editor, cx| {
20064                        let autoscroll = match scroll_offset {
20065                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20066                            None => Autoscroll::newest(),
20067                        };
20068                        let nav_history = editor.nav_history.take();
20069                        editor.change_selections(
20070                            SelectionEffects::scroll(autoscroll),
20071                            window,
20072                            cx,
20073                            |s| {
20074                                s.select_ranges(ranges);
20075                            },
20076                        );
20077                        editor.nav_history = nav_history;
20078                    });
20079                }
20080            })
20081        });
20082    }
20083
20084    // For now, don't allow opening excerpts in buffers that aren't backed by
20085    // regular project files.
20086    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20087        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20088    }
20089
20090    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20091        let snapshot = self.buffer.read(cx).read(cx);
20092        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20093        Some(
20094            ranges
20095                .iter()
20096                .map(move |range| {
20097                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20098                })
20099                .collect(),
20100        )
20101    }
20102
20103    fn selection_replacement_ranges(
20104        &self,
20105        range: Range<OffsetUtf16>,
20106        cx: &mut App,
20107    ) -> Vec<Range<OffsetUtf16>> {
20108        let selections = self.selections.all::<OffsetUtf16>(cx);
20109        let newest_selection = selections
20110            .iter()
20111            .max_by_key(|selection| selection.id)
20112            .unwrap();
20113        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20114        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20115        let snapshot = self.buffer.read(cx).read(cx);
20116        selections
20117            .into_iter()
20118            .map(|mut selection| {
20119                selection.start.0 =
20120                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20121                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20122                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20123                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20124            })
20125            .collect()
20126    }
20127
20128    fn report_editor_event(
20129        &self,
20130        event_type: &'static str,
20131        file_extension: Option<String>,
20132        cx: &App,
20133    ) {
20134        if cfg!(any(test, feature = "test-support")) {
20135            return;
20136        }
20137
20138        let Some(project) = &self.project else { return };
20139
20140        // If None, we are in a file without an extension
20141        let file = self
20142            .buffer
20143            .read(cx)
20144            .as_singleton()
20145            .and_then(|b| b.read(cx).file());
20146        let file_extension = file_extension.or(file
20147            .as_ref()
20148            .and_then(|file| Path::new(file.file_name(cx)).extension())
20149            .and_then(|e| e.to_str())
20150            .map(|a| a.to_string()));
20151
20152        let vim_mode = vim_enabled(cx);
20153
20154        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20155        let copilot_enabled = edit_predictions_provider
20156            == language::language_settings::EditPredictionProvider::Copilot;
20157        let copilot_enabled_for_language = self
20158            .buffer
20159            .read(cx)
20160            .language_settings(cx)
20161            .show_edit_predictions;
20162
20163        let project = project.read(cx);
20164        telemetry::event!(
20165            event_type,
20166            file_extension,
20167            vim_mode,
20168            copilot_enabled,
20169            copilot_enabled_for_language,
20170            edit_predictions_provider,
20171            is_via_ssh = project.is_via_ssh(),
20172        );
20173    }
20174
20175    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20176    /// with each line being an array of {text, highlight} objects.
20177    fn copy_highlight_json(
20178        &mut self,
20179        _: &CopyHighlightJson,
20180        window: &mut Window,
20181        cx: &mut Context<Self>,
20182    ) {
20183        #[derive(Serialize)]
20184        struct Chunk<'a> {
20185            text: String,
20186            highlight: Option<&'a str>,
20187        }
20188
20189        let snapshot = self.buffer.read(cx).snapshot(cx);
20190        let range = self
20191            .selected_text_range(false, window, cx)
20192            .and_then(|selection| {
20193                if selection.range.is_empty() {
20194                    None
20195                } else {
20196                    Some(selection.range)
20197                }
20198            })
20199            .unwrap_or_else(|| 0..snapshot.len());
20200
20201        let chunks = snapshot.chunks(range, true);
20202        let mut lines = Vec::new();
20203        let mut line: VecDeque<Chunk> = VecDeque::new();
20204
20205        let Some(style) = self.style.as_ref() else {
20206            return;
20207        };
20208
20209        for chunk in chunks {
20210            let highlight = chunk
20211                .syntax_highlight_id
20212                .and_then(|id| id.name(&style.syntax));
20213            let mut chunk_lines = chunk.text.split('\n').peekable();
20214            while let Some(text) = chunk_lines.next() {
20215                let mut merged_with_last_token = false;
20216                if let Some(last_token) = line.back_mut() {
20217                    if last_token.highlight == highlight {
20218                        last_token.text.push_str(text);
20219                        merged_with_last_token = true;
20220                    }
20221                }
20222
20223                if !merged_with_last_token {
20224                    line.push_back(Chunk {
20225                        text: text.into(),
20226                        highlight,
20227                    });
20228                }
20229
20230                if chunk_lines.peek().is_some() {
20231                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20232                        line.pop_front();
20233                    }
20234                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20235                        line.pop_back();
20236                    }
20237
20238                    lines.push(mem::take(&mut line));
20239                }
20240            }
20241        }
20242
20243        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20244            return;
20245        };
20246        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20247    }
20248
20249    pub fn open_context_menu(
20250        &mut self,
20251        _: &OpenContextMenu,
20252        window: &mut Window,
20253        cx: &mut Context<Self>,
20254    ) {
20255        self.request_autoscroll(Autoscroll::newest(), cx);
20256        let position = self.selections.newest_display(cx).start;
20257        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20258    }
20259
20260    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20261        &self.inlay_hint_cache
20262    }
20263
20264    pub fn replay_insert_event(
20265        &mut self,
20266        text: &str,
20267        relative_utf16_range: Option<Range<isize>>,
20268        window: &mut Window,
20269        cx: &mut Context<Self>,
20270    ) {
20271        if !self.input_enabled {
20272            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20273            return;
20274        }
20275        if let Some(relative_utf16_range) = relative_utf16_range {
20276            let selections = self.selections.all::<OffsetUtf16>(cx);
20277            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20278                let new_ranges = selections.into_iter().map(|range| {
20279                    let start = OffsetUtf16(
20280                        range
20281                            .head()
20282                            .0
20283                            .saturating_add_signed(relative_utf16_range.start),
20284                    );
20285                    let end = OffsetUtf16(
20286                        range
20287                            .head()
20288                            .0
20289                            .saturating_add_signed(relative_utf16_range.end),
20290                    );
20291                    start..end
20292                });
20293                s.select_ranges(new_ranges);
20294            });
20295        }
20296
20297        self.handle_input(text, window, cx);
20298    }
20299
20300    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20301        let Some(provider) = self.semantics_provider.as_ref() else {
20302            return false;
20303        };
20304
20305        let mut supports = false;
20306        self.buffer().update(cx, |this, cx| {
20307            this.for_each_buffer(|buffer| {
20308                supports |= provider.supports_inlay_hints(buffer, cx);
20309            });
20310        });
20311
20312        supports
20313    }
20314
20315    pub fn is_focused(&self, window: &Window) -> bool {
20316        self.focus_handle.is_focused(window)
20317    }
20318
20319    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20320        cx.emit(EditorEvent::Focused);
20321
20322        if let Some(descendant) = self
20323            .last_focused_descendant
20324            .take()
20325            .and_then(|descendant| descendant.upgrade())
20326        {
20327            window.focus(&descendant);
20328        } else {
20329            if let Some(blame) = self.blame.as_ref() {
20330                blame.update(cx, GitBlame::focus)
20331            }
20332
20333            self.blink_manager.update(cx, BlinkManager::enable);
20334            self.show_cursor_names(window, cx);
20335            self.buffer.update(cx, |buffer, cx| {
20336                buffer.finalize_last_transaction(cx);
20337                if self.leader_id.is_none() {
20338                    buffer.set_active_selections(
20339                        &self.selections.disjoint_anchors(),
20340                        self.selections.line_mode,
20341                        self.cursor_shape,
20342                        cx,
20343                    );
20344                }
20345            });
20346        }
20347    }
20348
20349    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20350        cx.emit(EditorEvent::FocusedIn)
20351    }
20352
20353    fn handle_focus_out(
20354        &mut self,
20355        event: FocusOutEvent,
20356        _window: &mut Window,
20357        cx: &mut Context<Self>,
20358    ) {
20359        if event.blurred != self.focus_handle {
20360            self.last_focused_descendant = Some(event.blurred);
20361        }
20362        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20363    }
20364
20365    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20366        self.blink_manager.update(cx, BlinkManager::disable);
20367        self.buffer
20368            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20369
20370        if let Some(blame) = self.blame.as_ref() {
20371            blame.update(cx, GitBlame::blur)
20372        }
20373        if !self.hover_state.focused(window, cx) {
20374            hide_hover(self, cx);
20375        }
20376        if !self
20377            .context_menu
20378            .borrow()
20379            .as_ref()
20380            .is_some_and(|context_menu| context_menu.focused(window, cx))
20381        {
20382            self.hide_context_menu(window, cx);
20383        }
20384        self.discard_inline_completion(false, cx);
20385        cx.emit(EditorEvent::Blurred);
20386        cx.notify();
20387    }
20388
20389    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20390        let mut pending: String = window
20391            .pending_input_keystrokes()
20392            .into_iter()
20393            .flatten()
20394            .filter_map(|keystroke| {
20395                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20396                    keystroke.key_char.clone()
20397                } else {
20398                    None
20399                }
20400            })
20401            .collect();
20402
20403        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20404            pending = "".to_string();
20405        }
20406
20407        let existing_pending = self
20408            .text_highlights::<PendingInput>(cx)
20409            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20410        if existing_pending.is_none() && pending.is_empty() {
20411            return;
20412        }
20413        let transaction =
20414            self.transact(window, cx, |this, window, cx| {
20415                let selections = this.selections.all::<usize>(cx);
20416                let edits = selections
20417                    .iter()
20418                    .map(|selection| (selection.end..selection.end, pending.clone()));
20419                this.edit(edits, cx);
20420                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20421                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20422                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20423                    }));
20424                });
20425                if let Some(existing_ranges) = existing_pending {
20426                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20427                    this.edit(edits, cx);
20428                }
20429            });
20430
20431        let snapshot = self.snapshot(window, cx);
20432        let ranges = self
20433            .selections
20434            .all::<usize>(cx)
20435            .into_iter()
20436            .map(|selection| {
20437                snapshot.buffer_snapshot.anchor_after(selection.end)
20438                    ..snapshot
20439                        .buffer_snapshot
20440                        .anchor_before(selection.end + pending.len())
20441            })
20442            .collect();
20443
20444        if pending.is_empty() {
20445            self.clear_highlights::<PendingInput>(cx);
20446        } else {
20447            self.highlight_text::<PendingInput>(
20448                ranges,
20449                HighlightStyle {
20450                    underline: Some(UnderlineStyle {
20451                        thickness: px(1.),
20452                        color: None,
20453                        wavy: false,
20454                    }),
20455                    ..Default::default()
20456                },
20457                cx,
20458            );
20459        }
20460
20461        self.ime_transaction = self.ime_transaction.or(transaction);
20462        if let Some(transaction) = self.ime_transaction {
20463            self.buffer.update(cx, |buffer, cx| {
20464                buffer.group_until_transaction(transaction, cx);
20465            });
20466        }
20467
20468        if self.text_highlights::<PendingInput>(cx).is_none() {
20469            self.ime_transaction.take();
20470        }
20471    }
20472
20473    pub fn register_action_renderer(
20474        &mut self,
20475        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20476    ) -> Subscription {
20477        let id = self.next_editor_action_id.post_inc();
20478        self.editor_actions
20479            .borrow_mut()
20480            .insert(id, Box::new(listener));
20481
20482        let editor_actions = self.editor_actions.clone();
20483        Subscription::new(move || {
20484            editor_actions.borrow_mut().remove(&id);
20485        })
20486    }
20487
20488    pub fn register_action<A: Action>(
20489        &mut self,
20490        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20491    ) -> Subscription {
20492        let id = self.next_editor_action_id.post_inc();
20493        let listener = Arc::new(listener);
20494        self.editor_actions.borrow_mut().insert(
20495            id,
20496            Box::new(move |_, window, _| {
20497                let listener = listener.clone();
20498                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20499                    let action = action.downcast_ref().unwrap();
20500                    if phase == DispatchPhase::Bubble {
20501                        listener(action, window, cx)
20502                    }
20503                })
20504            }),
20505        );
20506
20507        let editor_actions = self.editor_actions.clone();
20508        Subscription::new(move || {
20509            editor_actions.borrow_mut().remove(&id);
20510        })
20511    }
20512
20513    pub fn file_header_size(&self) -> u32 {
20514        FILE_HEADER_HEIGHT
20515    }
20516
20517    pub fn restore(
20518        &mut self,
20519        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20520        window: &mut Window,
20521        cx: &mut Context<Self>,
20522    ) {
20523        let workspace = self.workspace();
20524        let project = self.project.as_ref();
20525        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20526            let mut tasks = Vec::new();
20527            for (buffer_id, changes) in revert_changes {
20528                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20529                    buffer.update(cx, |buffer, cx| {
20530                        buffer.edit(
20531                            changes
20532                                .into_iter()
20533                                .map(|(range, text)| (range, text.to_string())),
20534                            None,
20535                            cx,
20536                        );
20537                    });
20538
20539                    if let Some(project) =
20540                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20541                    {
20542                        project.update(cx, |project, cx| {
20543                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20544                        })
20545                    }
20546                }
20547            }
20548            tasks
20549        });
20550        cx.spawn_in(window, async move |_, cx| {
20551            for (buffer, task) in save_tasks {
20552                let result = task.await;
20553                if result.is_err() {
20554                    let Some(path) = buffer
20555                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20556                        .ok()
20557                    else {
20558                        continue;
20559                    };
20560                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20561                        let Some(task) = cx
20562                            .update_window_entity(&workspace, |workspace, window, cx| {
20563                                workspace
20564                                    .open_path_preview(path, None, false, false, false, window, cx)
20565                            })
20566                            .ok()
20567                        else {
20568                            continue;
20569                        };
20570                        task.await.log_err();
20571                    }
20572                }
20573            }
20574        })
20575        .detach();
20576        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20577            selections.refresh()
20578        });
20579    }
20580
20581    pub fn to_pixel_point(
20582        &self,
20583        source: multi_buffer::Anchor,
20584        editor_snapshot: &EditorSnapshot,
20585        window: &mut Window,
20586    ) -> Option<gpui::Point<Pixels>> {
20587        let source_point = source.to_display_point(editor_snapshot);
20588        self.display_to_pixel_point(source_point, editor_snapshot, window)
20589    }
20590
20591    pub fn display_to_pixel_point(
20592        &self,
20593        source: DisplayPoint,
20594        editor_snapshot: &EditorSnapshot,
20595        window: &mut Window,
20596    ) -> Option<gpui::Point<Pixels>> {
20597        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20598        let text_layout_details = self.text_layout_details(window);
20599        let scroll_top = text_layout_details
20600            .scroll_anchor
20601            .scroll_position(editor_snapshot)
20602            .y;
20603
20604        if source.row().as_f32() < scroll_top.floor() {
20605            return None;
20606        }
20607        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20608        let source_y = line_height * (source.row().as_f32() - scroll_top);
20609        Some(gpui::Point::new(source_x, source_y))
20610    }
20611
20612    pub fn has_visible_completions_menu(&self) -> bool {
20613        !self.edit_prediction_preview_is_active()
20614            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20615                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20616            })
20617    }
20618
20619    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20620        if self.mode.is_minimap() {
20621            return;
20622        }
20623        self.addons
20624            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20625    }
20626
20627    pub fn unregister_addon<T: Addon>(&mut self) {
20628        self.addons.remove(&std::any::TypeId::of::<T>());
20629    }
20630
20631    pub fn addon<T: Addon>(&self) -> Option<&T> {
20632        let type_id = std::any::TypeId::of::<T>();
20633        self.addons
20634            .get(&type_id)
20635            .and_then(|item| item.to_any().downcast_ref::<T>())
20636    }
20637
20638    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20639        let type_id = std::any::TypeId::of::<T>();
20640        self.addons
20641            .get_mut(&type_id)
20642            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20643    }
20644
20645    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20646        let text_layout_details = self.text_layout_details(window);
20647        let style = &text_layout_details.editor_style;
20648        let font_id = window.text_system().resolve_font(&style.text.font());
20649        let font_size = style.text.font_size.to_pixels(window.rem_size());
20650        let line_height = style.text.line_height_in_pixels(window.rem_size());
20651        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20652        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20653
20654        CharacterDimensions {
20655            em_width,
20656            em_advance,
20657            line_height,
20658        }
20659    }
20660
20661    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20662        self.load_diff_task.clone()
20663    }
20664
20665    fn read_metadata_from_db(
20666        &mut self,
20667        item_id: u64,
20668        workspace_id: WorkspaceId,
20669        window: &mut Window,
20670        cx: &mut Context<Editor>,
20671    ) {
20672        if self.is_singleton(cx)
20673            && !self.mode.is_minimap()
20674            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20675        {
20676            let buffer_snapshot = OnceCell::new();
20677
20678            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20679                if !folds.is_empty() {
20680                    let snapshot =
20681                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20682                    self.fold_ranges(
20683                        folds
20684                            .into_iter()
20685                            .map(|(start, end)| {
20686                                snapshot.clip_offset(start, Bias::Left)
20687                                    ..snapshot.clip_offset(end, Bias::Right)
20688                            })
20689                            .collect(),
20690                        false,
20691                        window,
20692                        cx,
20693                    );
20694                }
20695            }
20696
20697            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20698                if !selections.is_empty() {
20699                    let snapshot =
20700                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20701                    // skip adding the initial selection to selection history
20702                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20703                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20704                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20705                            snapshot.clip_offset(start, Bias::Left)
20706                                ..snapshot.clip_offset(end, Bias::Right)
20707                        }));
20708                    });
20709                    self.selection_history.mode = SelectionHistoryMode::Normal;
20710                }
20711            };
20712        }
20713
20714        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20715    }
20716
20717    fn update_lsp_data(
20718        &mut self,
20719        ignore_cache: bool,
20720        for_buffer: Option<BufferId>,
20721        window: &mut Window,
20722        cx: &mut Context<'_, Self>,
20723    ) {
20724        self.pull_diagnostics(for_buffer, window, cx);
20725        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20726    }
20727}
20728
20729fn vim_enabled(cx: &App) -> bool {
20730    cx.global::<SettingsStore>()
20731        .raw_user_settings()
20732        .get("vim_mode")
20733        == Some(&serde_json::Value::Bool(true))
20734}
20735
20736fn process_completion_for_edit(
20737    completion: &Completion,
20738    intent: CompletionIntent,
20739    buffer: &Entity<Buffer>,
20740    cursor_position: &text::Anchor,
20741    cx: &mut Context<Editor>,
20742) -> CompletionEdit {
20743    let buffer = buffer.read(cx);
20744    let buffer_snapshot = buffer.snapshot();
20745    let (snippet, new_text) = if completion.is_snippet() {
20746        // Workaround for typescript language server issues so that methods don't expand within
20747        // strings and functions with type expressions. The previous point is used because the query
20748        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20749        let mut snippet_source = completion.new_text.clone();
20750        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20751        previous_point.column = previous_point.column.saturating_sub(1);
20752        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20753            if scope.prefers_label_for_snippet_in_completion() {
20754                if let Some(label) = completion.label() {
20755                    if matches!(
20756                        completion.kind(),
20757                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20758                    ) {
20759                        snippet_source = label;
20760                    }
20761                }
20762            }
20763        }
20764        match Snippet::parse(&snippet_source).log_err() {
20765            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20766            None => (None, completion.new_text.clone()),
20767        }
20768    } else {
20769        (None, completion.new_text.clone())
20770    };
20771
20772    let mut range_to_replace = {
20773        let replace_range = &completion.replace_range;
20774        if let CompletionSource::Lsp {
20775            insert_range: Some(insert_range),
20776            ..
20777        } = &completion.source
20778        {
20779            debug_assert_eq!(
20780                insert_range.start, replace_range.start,
20781                "insert_range and replace_range should start at the same position"
20782            );
20783            debug_assert!(
20784                insert_range
20785                    .start
20786                    .cmp(&cursor_position, &buffer_snapshot)
20787                    .is_le(),
20788                "insert_range should start before or at cursor position"
20789            );
20790            debug_assert!(
20791                replace_range
20792                    .start
20793                    .cmp(&cursor_position, &buffer_snapshot)
20794                    .is_le(),
20795                "replace_range should start before or at cursor position"
20796            );
20797            debug_assert!(
20798                insert_range
20799                    .end
20800                    .cmp(&cursor_position, &buffer_snapshot)
20801                    .is_le(),
20802                "insert_range should end before or at cursor position"
20803            );
20804
20805            let should_replace = match intent {
20806                CompletionIntent::CompleteWithInsert => false,
20807                CompletionIntent::CompleteWithReplace => true,
20808                CompletionIntent::Complete | CompletionIntent::Compose => {
20809                    let insert_mode =
20810                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20811                            .completions
20812                            .lsp_insert_mode;
20813                    match insert_mode {
20814                        LspInsertMode::Insert => false,
20815                        LspInsertMode::Replace => true,
20816                        LspInsertMode::ReplaceSubsequence => {
20817                            let mut text_to_replace = buffer.chars_for_range(
20818                                buffer.anchor_before(replace_range.start)
20819                                    ..buffer.anchor_after(replace_range.end),
20820                            );
20821                            let mut current_needle = text_to_replace.next();
20822                            for haystack_ch in completion.label.text.chars() {
20823                                if let Some(needle_ch) = current_needle {
20824                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20825                                        current_needle = text_to_replace.next();
20826                                    }
20827                                }
20828                            }
20829                            current_needle.is_none()
20830                        }
20831                        LspInsertMode::ReplaceSuffix => {
20832                            if replace_range
20833                                .end
20834                                .cmp(&cursor_position, &buffer_snapshot)
20835                                .is_gt()
20836                            {
20837                                let range_after_cursor = *cursor_position..replace_range.end;
20838                                let text_after_cursor = buffer
20839                                    .text_for_range(
20840                                        buffer.anchor_before(range_after_cursor.start)
20841                                            ..buffer.anchor_after(range_after_cursor.end),
20842                                    )
20843                                    .collect::<String>()
20844                                    .to_ascii_lowercase();
20845                                completion
20846                                    .label
20847                                    .text
20848                                    .to_ascii_lowercase()
20849                                    .ends_with(&text_after_cursor)
20850                            } else {
20851                                true
20852                            }
20853                        }
20854                    }
20855                }
20856            };
20857
20858            if should_replace {
20859                replace_range.clone()
20860            } else {
20861                insert_range.clone()
20862            }
20863        } else {
20864            replace_range.clone()
20865        }
20866    };
20867
20868    if range_to_replace
20869        .end
20870        .cmp(&cursor_position, &buffer_snapshot)
20871        .is_lt()
20872    {
20873        range_to_replace.end = *cursor_position;
20874    }
20875
20876    CompletionEdit {
20877        new_text,
20878        replace_range: range_to_replace.to_offset(&buffer),
20879        snippet,
20880    }
20881}
20882
20883struct CompletionEdit {
20884    new_text: String,
20885    replace_range: Range<usize>,
20886    snippet: Option<Snippet>,
20887}
20888
20889fn insert_extra_newline_brackets(
20890    buffer: &MultiBufferSnapshot,
20891    range: Range<usize>,
20892    language: &language::LanguageScope,
20893) -> bool {
20894    let leading_whitespace_len = buffer
20895        .reversed_chars_at(range.start)
20896        .take_while(|c| c.is_whitespace() && *c != '\n')
20897        .map(|c| c.len_utf8())
20898        .sum::<usize>();
20899    let trailing_whitespace_len = buffer
20900        .chars_at(range.end)
20901        .take_while(|c| c.is_whitespace() && *c != '\n')
20902        .map(|c| c.len_utf8())
20903        .sum::<usize>();
20904    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20905
20906    language.brackets().any(|(pair, enabled)| {
20907        let pair_start = pair.start.trim_end();
20908        let pair_end = pair.end.trim_start();
20909
20910        enabled
20911            && pair.newline
20912            && buffer.contains_str_at(range.end, pair_end)
20913            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20914    })
20915}
20916
20917fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20918    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20919        [(buffer, range, _)] => (*buffer, range.clone()),
20920        _ => return false,
20921    };
20922    let pair = {
20923        let mut result: Option<BracketMatch> = None;
20924
20925        for pair in buffer
20926            .all_bracket_ranges(range.clone())
20927            .filter(move |pair| {
20928                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20929            })
20930        {
20931            let len = pair.close_range.end - pair.open_range.start;
20932
20933            if let Some(existing) = &result {
20934                let existing_len = existing.close_range.end - existing.open_range.start;
20935                if len > existing_len {
20936                    continue;
20937                }
20938            }
20939
20940            result = Some(pair);
20941        }
20942
20943        result
20944    };
20945    let Some(pair) = pair else {
20946        return false;
20947    };
20948    pair.newline_only
20949        && buffer
20950            .chars_for_range(pair.open_range.end..range.start)
20951            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20952            .all(|c| c.is_whitespace() && c != '\n')
20953}
20954
20955fn update_uncommitted_diff_for_buffer(
20956    editor: Entity<Editor>,
20957    project: &Entity<Project>,
20958    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20959    buffer: Entity<MultiBuffer>,
20960    cx: &mut App,
20961) -> Task<()> {
20962    let mut tasks = Vec::new();
20963    project.update(cx, |project, cx| {
20964        for buffer in buffers {
20965            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20966                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20967            }
20968        }
20969    });
20970    cx.spawn(async move |cx| {
20971        let diffs = future::join_all(tasks).await;
20972        if editor
20973            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20974            .unwrap_or(false)
20975        {
20976            return;
20977        }
20978
20979        buffer
20980            .update(cx, |buffer, cx| {
20981                for diff in diffs.into_iter().flatten() {
20982                    buffer.add_diff(diff, cx);
20983                }
20984            })
20985            .ok();
20986    })
20987}
20988
20989fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20990    let tab_size = tab_size.get() as usize;
20991    let mut width = offset;
20992
20993    for ch in text.chars() {
20994        width += if ch == '\t' {
20995            tab_size - (width % tab_size)
20996        } else {
20997            1
20998        };
20999    }
21000
21001    width - offset
21002}
21003
21004#[cfg(test)]
21005mod tests {
21006    use super::*;
21007
21008    #[test]
21009    fn test_string_size_with_expanded_tabs() {
21010        let nz = |val| NonZeroU32::new(val).unwrap();
21011        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21012        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21013        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21014        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21015        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21016        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21017        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21018        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21019    }
21020}
21021
21022/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21023struct WordBreakingTokenizer<'a> {
21024    input: &'a str,
21025}
21026
21027impl<'a> WordBreakingTokenizer<'a> {
21028    fn new(input: &'a str) -> Self {
21029        Self { input }
21030    }
21031}
21032
21033fn is_char_ideographic(ch: char) -> bool {
21034    use unicode_script::Script::*;
21035    use unicode_script::UnicodeScript;
21036    matches!(ch.script(), Han | Tangut | Yi)
21037}
21038
21039fn is_grapheme_ideographic(text: &str) -> bool {
21040    text.chars().any(is_char_ideographic)
21041}
21042
21043fn is_grapheme_whitespace(text: &str) -> bool {
21044    text.chars().any(|x| x.is_whitespace())
21045}
21046
21047fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21048    text.chars().next().map_or(false, |ch| {
21049        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21050    })
21051}
21052
21053#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21054enum WordBreakToken<'a> {
21055    Word { token: &'a str, grapheme_len: usize },
21056    InlineWhitespace { token: &'a str, grapheme_len: usize },
21057    Newline,
21058}
21059
21060impl<'a> Iterator for WordBreakingTokenizer<'a> {
21061    /// Yields a span, the count of graphemes in the token, and whether it was
21062    /// whitespace. Note that it also breaks at word boundaries.
21063    type Item = WordBreakToken<'a>;
21064
21065    fn next(&mut self) -> Option<Self::Item> {
21066        use unicode_segmentation::UnicodeSegmentation;
21067        if self.input.is_empty() {
21068            return None;
21069        }
21070
21071        let mut iter = self.input.graphemes(true).peekable();
21072        let mut offset = 0;
21073        let mut grapheme_len = 0;
21074        if let Some(first_grapheme) = iter.next() {
21075            let is_newline = first_grapheme == "\n";
21076            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21077            offset += first_grapheme.len();
21078            grapheme_len += 1;
21079            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21080                if let Some(grapheme) = iter.peek().copied() {
21081                    if should_stay_with_preceding_ideograph(grapheme) {
21082                        offset += grapheme.len();
21083                        grapheme_len += 1;
21084                    }
21085                }
21086            } else {
21087                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21088                let mut next_word_bound = words.peek().copied();
21089                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21090                    next_word_bound = words.next();
21091                }
21092                while let Some(grapheme) = iter.peek().copied() {
21093                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21094                        break;
21095                    };
21096                    if is_grapheme_whitespace(grapheme) != is_whitespace
21097                        || (grapheme == "\n") != is_newline
21098                    {
21099                        break;
21100                    };
21101                    offset += grapheme.len();
21102                    grapheme_len += 1;
21103                    iter.next();
21104                }
21105            }
21106            let token = &self.input[..offset];
21107            self.input = &self.input[offset..];
21108            if token == "\n" {
21109                Some(WordBreakToken::Newline)
21110            } else if is_whitespace {
21111                Some(WordBreakToken::InlineWhitespace {
21112                    token,
21113                    grapheme_len,
21114                })
21115            } else {
21116                Some(WordBreakToken::Word {
21117                    token,
21118                    grapheme_len,
21119                })
21120            }
21121        } else {
21122            None
21123        }
21124    }
21125}
21126
21127#[test]
21128fn test_word_breaking_tokenizer() {
21129    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21130        ("", &[]),
21131        ("  ", &[whitespace("  ", 2)]),
21132        ("Ʒ", &[word("Ʒ", 1)]),
21133        ("Ǽ", &[word("Ǽ", 1)]),
21134        ("", &[word("", 1)]),
21135        ("⋑⋑", &[word("⋑⋑", 2)]),
21136        (
21137            "原理,进而",
21138            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21139        ),
21140        (
21141            "hello world",
21142            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21143        ),
21144        (
21145            "hello, world",
21146            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21147        ),
21148        (
21149            "  hello world",
21150            &[
21151                whitespace("  ", 2),
21152                word("hello", 5),
21153                whitespace(" ", 1),
21154                word("world", 5),
21155            ],
21156        ),
21157        (
21158            "这是什么 \n 钢笔",
21159            &[
21160                word("", 1),
21161                word("", 1),
21162                word("", 1),
21163                word("", 1),
21164                whitespace(" ", 1),
21165                newline(),
21166                whitespace(" ", 1),
21167                word("", 1),
21168                word("", 1),
21169            ],
21170        ),
21171        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21172    ];
21173
21174    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21175        WordBreakToken::Word {
21176            token,
21177            grapheme_len,
21178        }
21179    }
21180
21181    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21182        WordBreakToken::InlineWhitespace {
21183            token,
21184            grapheme_len,
21185        }
21186    }
21187
21188    fn newline() -> WordBreakToken<'static> {
21189        WordBreakToken::Newline
21190    }
21191
21192    for (input, result) in tests {
21193        assert_eq!(
21194            WordBreakingTokenizer::new(input)
21195                .collect::<Vec<_>>()
21196                .as_slice(),
21197            *result,
21198        );
21199    }
21200}
21201
21202fn wrap_with_prefix(
21203    line_prefix: String,
21204    unwrapped_text: String,
21205    wrap_column: usize,
21206    tab_size: NonZeroU32,
21207    preserve_existing_whitespace: bool,
21208) -> String {
21209    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
21210    let mut wrapped_text = String::new();
21211    let mut current_line = line_prefix.clone();
21212
21213    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21214    let mut current_line_len = line_prefix_len;
21215    let mut in_whitespace = false;
21216    for token in tokenizer {
21217        let have_preceding_whitespace = in_whitespace;
21218        match token {
21219            WordBreakToken::Word {
21220                token,
21221                grapheme_len,
21222            } => {
21223                in_whitespace = false;
21224                if current_line_len + grapheme_len > wrap_column
21225                    && current_line_len != line_prefix_len
21226                {
21227                    wrapped_text.push_str(current_line.trim_end());
21228                    wrapped_text.push('\n');
21229                    current_line.truncate(line_prefix.len());
21230                    current_line_len = line_prefix_len;
21231                }
21232                current_line.push_str(token);
21233                current_line_len += grapheme_len;
21234            }
21235            WordBreakToken::InlineWhitespace {
21236                mut token,
21237                mut grapheme_len,
21238            } => {
21239                in_whitespace = true;
21240                if have_preceding_whitespace && !preserve_existing_whitespace {
21241                    continue;
21242                }
21243                if !preserve_existing_whitespace {
21244                    token = " ";
21245                    grapheme_len = 1;
21246                }
21247                if current_line_len + grapheme_len > wrap_column {
21248                    wrapped_text.push_str(current_line.trim_end());
21249                    wrapped_text.push('\n');
21250                    current_line.truncate(line_prefix.len());
21251                    current_line_len = line_prefix_len;
21252                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
21253                    current_line.push_str(token);
21254                    current_line_len += grapheme_len;
21255                }
21256            }
21257            WordBreakToken::Newline => {
21258                in_whitespace = true;
21259                if preserve_existing_whitespace {
21260                    wrapped_text.push_str(current_line.trim_end());
21261                    wrapped_text.push('\n');
21262                    current_line.truncate(line_prefix.len());
21263                    current_line_len = line_prefix_len;
21264                } else if have_preceding_whitespace {
21265                    continue;
21266                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
21267                {
21268                    wrapped_text.push_str(current_line.trim_end());
21269                    wrapped_text.push('\n');
21270                    current_line.truncate(line_prefix.len());
21271                    current_line_len = line_prefix_len;
21272                } else if current_line_len != line_prefix_len {
21273                    current_line.push(' ');
21274                    current_line_len += 1;
21275                }
21276            }
21277        }
21278    }
21279
21280    if !current_line.is_empty() {
21281        wrapped_text.push_str(&current_line);
21282    }
21283    wrapped_text
21284}
21285
21286#[test]
21287fn test_wrap_with_prefix() {
21288    assert_eq!(
21289        wrap_with_prefix(
21290            "# ".to_string(),
21291            "abcdefg".to_string(),
21292            4,
21293            NonZeroU32::new(4).unwrap(),
21294            false,
21295        ),
21296        "# abcdefg"
21297    );
21298    assert_eq!(
21299        wrap_with_prefix(
21300            "".to_string(),
21301            "\thello world".to_string(),
21302            8,
21303            NonZeroU32::new(4).unwrap(),
21304            false,
21305        ),
21306        "hello\nworld"
21307    );
21308    assert_eq!(
21309        wrap_with_prefix(
21310            "// ".to_string(),
21311            "xx \nyy zz aa bb cc".to_string(),
21312            12,
21313            NonZeroU32::new(4).unwrap(),
21314            false,
21315        ),
21316        "// xx yy zz\n// aa bb cc"
21317    );
21318    assert_eq!(
21319        wrap_with_prefix(
21320            String::new(),
21321            "这是什么 \n 钢笔".to_string(),
21322            3,
21323            NonZeroU32::new(4).unwrap(),
21324            false,
21325        ),
21326        "这是什\n么 钢\n"
21327    );
21328}
21329
21330pub trait CollaborationHub {
21331    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21332    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21333    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21334}
21335
21336impl CollaborationHub for Entity<Project> {
21337    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21338        self.read(cx).collaborators()
21339    }
21340
21341    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21342        self.read(cx).user_store().read(cx).participant_indices()
21343    }
21344
21345    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21346        let this = self.read(cx);
21347        let user_ids = this.collaborators().values().map(|c| c.user_id);
21348        this.user_store().read(cx).participant_names(user_ids, cx)
21349    }
21350}
21351
21352pub trait SemanticsProvider {
21353    fn hover(
21354        &self,
21355        buffer: &Entity<Buffer>,
21356        position: text::Anchor,
21357        cx: &mut App,
21358    ) -> Option<Task<Vec<project::Hover>>>;
21359
21360    fn inline_values(
21361        &self,
21362        buffer_handle: Entity<Buffer>,
21363        range: Range<text::Anchor>,
21364        cx: &mut App,
21365    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21366
21367    fn inlay_hints(
21368        &self,
21369        buffer_handle: Entity<Buffer>,
21370        range: Range<text::Anchor>,
21371        cx: &mut App,
21372    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21373
21374    fn resolve_inlay_hint(
21375        &self,
21376        hint: InlayHint,
21377        buffer_handle: Entity<Buffer>,
21378        server_id: LanguageServerId,
21379        cx: &mut App,
21380    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21381
21382    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21383
21384    fn document_highlights(
21385        &self,
21386        buffer: &Entity<Buffer>,
21387        position: text::Anchor,
21388        cx: &mut App,
21389    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21390
21391    fn definitions(
21392        &self,
21393        buffer: &Entity<Buffer>,
21394        position: text::Anchor,
21395        kind: GotoDefinitionKind,
21396        cx: &mut App,
21397    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21398
21399    fn range_for_rename(
21400        &self,
21401        buffer: &Entity<Buffer>,
21402        position: text::Anchor,
21403        cx: &mut App,
21404    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21405
21406    fn perform_rename(
21407        &self,
21408        buffer: &Entity<Buffer>,
21409        position: text::Anchor,
21410        new_name: String,
21411        cx: &mut App,
21412    ) -> Option<Task<Result<ProjectTransaction>>>;
21413}
21414
21415pub trait CompletionProvider {
21416    fn completions(
21417        &self,
21418        excerpt_id: ExcerptId,
21419        buffer: &Entity<Buffer>,
21420        buffer_position: text::Anchor,
21421        trigger: CompletionContext,
21422        window: &mut Window,
21423        cx: &mut Context<Editor>,
21424    ) -> Task<Result<Vec<CompletionResponse>>>;
21425
21426    fn resolve_completions(
21427        &self,
21428        _buffer: Entity<Buffer>,
21429        _completion_indices: Vec<usize>,
21430        _completions: Rc<RefCell<Box<[Completion]>>>,
21431        _cx: &mut Context<Editor>,
21432    ) -> Task<Result<bool>> {
21433        Task::ready(Ok(false))
21434    }
21435
21436    fn apply_additional_edits_for_completion(
21437        &self,
21438        _buffer: Entity<Buffer>,
21439        _completions: Rc<RefCell<Box<[Completion]>>>,
21440        _completion_index: usize,
21441        _push_to_history: bool,
21442        _cx: &mut Context<Editor>,
21443    ) -> Task<Result<Option<language::Transaction>>> {
21444        Task::ready(Ok(None))
21445    }
21446
21447    fn is_completion_trigger(
21448        &self,
21449        buffer: &Entity<Buffer>,
21450        position: language::Anchor,
21451        text: &str,
21452        trigger_in_words: bool,
21453        menu_is_open: bool,
21454        cx: &mut Context<Editor>,
21455    ) -> bool;
21456
21457    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21458
21459    fn sort_completions(&self) -> bool {
21460        true
21461    }
21462
21463    fn filter_completions(&self) -> bool {
21464        true
21465    }
21466}
21467
21468pub trait CodeActionProvider {
21469    fn id(&self) -> Arc<str>;
21470
21471    fn code_actions(
21472        &self,
21473        buffer: &Entity<Buffer>,
21474        range: Range<text::Anchor>,
21475        window: &mut Window,
21476        cx: &mut App,
21477    ) -> Task<Result<Vec<CodeAction>>>;
21478
21479    fn apply_code_action(
21480        &self,
21481        buffer_handle: Entity<Buffer>,
21482        action: CodeAction,
21483        excerpt_id: ExcerptId,
21484        push_to_history: bool,
21485        window: &mut Window,
21486        cx: &mut App,
21487    ) -> Task<Result<ProjectTransaction>>;
21488}
21489
21490impl CodeActionProvider for Entity<Project> {
21491    fn id(&self) -> Arc<str> {
21492        "project".into()
21493    }
21494
21495    fn code_actions(
21496        &self,
21497        buffer: &Entity<Buffer>,
21498        range: Range<text::Anchor>,
21499        _window: &mut Window,
21500        cx: &mut App,
21501    ) -> Task<Result<Vec<CodeAction>>> {
21502        self.update(cx, |project, cx| {
21503            let code_lens = project.code_lens(buffer, range.clone(), cx);
21504            let code_actions = project.code_actions(buffer, range, None, cx);
21505            cx.background_spawn(async move {
21506                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21507                Ok(code_lens
21508                    .context("code lens fetch")?
21509                    .into_iter()
21510                    .chain(code_actions.context("code action fetch")?)
21511                    .collect())
21512            })
21513        })
21514    }
21515
21516    fn apply_code_action(
21517        &self,
21518        buffer_handle: Entity<Buffer>,
21519        action: CodeAction,
21520        _excerpt_id: ExcerptId,
21521        push_to_history: bool,
21522        _window: &mut Window,
21523        cx: &mut App,
21524    ) -> Task<Result<ProjectTransaction>> {
21525        self.update(cx, |project, cx| {
21526            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21527        })
21528    }
21529}
21530
21531fn snippet_completions(
21532    project: &Project,
21533    buffer: &Entity<Buffer>,
21534    buffer_position: text::Anchor,
21535    cx: &mut App,
21536) -> Task<Result<CompletionResponse>> {
21537    let languages = buffer.read(cx).languages_at(buffer_position);
21538    let snippet_store = project.snippets().read(cx);
21539
21540    let scopes: Vec<_> = languages
21541        .iter()
21542        .filter_map(|language| {
21543            let language_name = language.lsp_id();
21544            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21545
21546            if snippets.is_empty() {
21547                None
21548            } else {
21549                Some((language.default_scope(), snippets))
21550            }
21551        })
21552        .collect();
21553
21554    if scopes.is_empty() {
21555        return Task::ready(Ok(CompletionResponse {
21556            completions: vec![],
21557            is_incomplete: false,
21558        }));
21559    }
21560
21561    let snapshot = buffer.read(cx).text_snapshot();
21562    let chars: String = snapshot
21563        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21564        .collect();
21565    let executor = cx.background_executor().clone();
21566
21567    cx.background_spawn(async move {
21568        let mut is_incomplete = false;
21569        let mut completions: Vec<Completion> = Vec::new();
21570        for (scope, snippets) in scopes.into_iter() {
21571            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21572            let mut last_word = chars
21573                .chars()
21574                .take_while(|c| classifier.is_word(*c))
21575                .collect::<String>();
21576            last_word = last_word.chars().rev().collect();
21577
21578            if last_word.is_empty() {
21579                return Ok(CompletionResponse {
21580                    completions: vec![],
21581                    is_incomplete: true,
21582                });
21583            }
21584
21585            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21586            let to_lsp = |point: &text::Anchor| {
21587                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21588                point_to_lsp(end)
21589            };
21590            let lsp_end = to_lsp(&buffer_position);
21591
21592            let candidates = snippets
21593                .iter()
21594                .enumerate()
21595                .flat_map(|(ix, snippet)| {
21596                    snippet
21597                        .prefix
21598                        .iter()
21599                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21600                })
21601                .collect::<Vec<StringMatchCandidate>>();
21602
21603            const MAX_RESULTS: usize = 100;
21604            let mut matches = fuzzy::match_strings(
21605                &candidates,
21606                &last_word,
21607                last_word.chars().any(|c| c.is_uppercase()),
21608                true,
21609                MAX_RESULTS,
21610                &Default::default(),
21611                executor.clone(),
21612            )
21613            .await;
21614
21615            if matches.len() >= MAX_RESULTS {
21616                is_incomplete = true;
21617            }
21618
21619            // Remove all candidates where the query's start does not match the start of any word in the candidate
21620            if let Some(query_start) = last_word.chars().next() {
21621                matches.retain(|string_match| {
21622                    split_words(&string_match.string).any(|word| {
21623                        // Check that the first codepoint of the word as lowercase matches the first
21624                        // codepoint of the query as lowercase
21625                        word.chars()
21626                            .flat_map(|codepoint| codepoint.to_lowercase())
21627                            .zip(query_start.to_lowercase())
21628                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21629                    })
21630                });
21631            }
21632
21633            let matched_strings = matches
21634                .into_iter()
21635                .map(|m| m.string)
21636                .collect::<HashSet<_>>();
21637
21638            completions.extend(snippets.iter().filter_map(|snippet| {
21639                let matching_prefix = snippet
21640                    .prefix
21641                    .iter()
21642                    .find(|prefix| matched_strings.contains(*prefix))?;
21643                let start = as_offset - last_word.len();
21644                let start = snapshot.anchor_before(start);
21645                let range = start..buffer_position;
21646                let lsp_start = to_lsp(&start);
21647                let lsp_range = lsp::Range {
21648                    start: lsp_start,
21649                    end: lsp_end,
21650                };
21651                Some(Completion {
21652                    replace_range: range,
21653                    new_text: snippet.body.clone(),
21654                    source: CompletionSource::Lsp {
21655                        insert_range: None,
21656                        server_id: LanguageServerId(usize::MAX),
21657                        resolved: true,
21658                        lsp_completion: Box::new(lsp::CompletionItem {
21659                            label: snippet.prefix.first().unwrap().clone(),
21660                            kind: Some(CompletionItemKind::SNIPPET),
21661                            label_details: snippet.description.as_ref().map(|description| {
21662                                lsp::CompletionItemLabelDetails {
21663                                    detail: Some(description.clone()),
21664                                    description: None,
21665                                }
21666                            }),
21667                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21668                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21669                                lsp::InsertReplaceEdit {
21670                                    new_text: snippet.body.clone(),
21671                                    insert: lsp_range,
21672                                    replace: lsp_range,
21673                                },
21674                            )),
21675                            filter_text: Some(snippet.body.clone()),
21676                            sort_text: Some(char::MAX.to_string()),
21677                            ..lsp::CompletionItem::default()
21678                        }),
21679                        lsp_defaults: None,
21680                    },
21681                    label: CodeLabel {
21682                        text: matching_prefix.clone(),
21683                        runs: Vec::new(),
21684                        filter_range: 0..matching_prefix.len(),
21685                    },
21686                    icon_path: None,
21687                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21688                        single_line: snippet.name.clone().into(),
21689                        plain_text: snippet
21690                            .description
21691                            .clone()
21692                            .map(|description| description.into()),
21693                    }),
21694                    insert_text_mode: None,
21695                    confirm: None,
21696                })
21697            }))
21698        }
21699
21700        Ok(CompletionResponse {
21701            completions,
21702            is_incomplete,
21703        })
21704    })
21705}
21706
21707impl CompletionProvider for Entity<Project> {
21708    fn completions(
21709        &self,
21710        _excerpt_id: ExcerptId,
21711        buffer: &Entity<Buffer>,
21712        buffer_position: text::Anchor,
21713        options: CompletionContext,
21714        _window: &mut Window,
21715        cx: &mut Context<Editor>,
21716    ) -> Task<Result<Vec<CompletionResponse>>> {
21717        self.update(cx, |project, cx| {
21718            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21719            let project_completions = project.completions(buffer, buffer_position, options, cx);
21720            cx.background_spawn(async move {
21721                let mut responses = project_completions.await?;
21722                let snippets = snippets.await?;
21723                if !snippets.completions.is_empty() {
21724                    responses.push(snippets);
21725                }
21726                Ok(responses)
21727            })
21728        })
21729    }
21730
21731    fn resolve_completions(
21732        &self,
21733        buffer: Entity<Buffer>,
21734        completion_indices: Vec<usize>,
21735        completions: Rc<RefCell<Box<[Completion]>>>,
21736        cx: &mut Context<Editor>,
21737    ) -> Task<Result<bool>> {
21738        self.update(cx, |project, cx| {
21739            project.lsp_store().update(cx, |lsp_store, cx| {
21740                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21741            })
21742        })
21743    }
21744
21745    fn apply_additional_edits_for_completion(
21746        &self,
21747        buffer: Entity<Buffer>,
21748        completions: Rc<RefCell<Box<[Completion]>>>,
21749        completion_index: usize,
21750        push_to_history: bool,
21751        cx: &mut Context<Editor>,
21752    ) -> Task<Result<Option<language::Transaction>>> {
21753        self.update(cx, |project, cx| {
21754            project.lsp_store().update(cx, |lsp_store, cx| {
21755                lsp_store.apply_additional_edits_for_completion(
21756                    buffer,
21757                    completions,
21758                    completion_index,
21759                    push_to_history,
21760                    cx,
21761                )
21762            })
21763        })
21764    }
21765
21766    fn is_completion_trigger(
21767        &self,
21768        buffer: &Entity<Buffer>,
21769        position: language::Anchor,
21770        text: &str,
21771        trigger_in_words: bool,
21772        menu_is_open: bool,
21773        cx: &mut Context<Editor>,
21774    ) -> bool {
21775        let mut chars = text.chars();
21776        let char = if let Some(char) = chars.next() {
21777            char
21778        } else {
21779            return false;
21780        };
21781        if chars.next().is_some() {
21782            return false;
21783        }
21784
21785        let buffer = buffer.read(cx);
21786        let snapshot = buffer.snapshot();
21787        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21788            return false;
21789        }
21790        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21791        if trigger_in_words && classifier.is_word(char) {
21792            return true;
21793        }
21794
21795        buffer.completion_triggers().contains(text)
21796    }
21797}
21798
21799impl SemanticsProvider for Entity<Project> {
21800    fn hover(
21801        &self,
21802        buffer: &Entity<Buffer>,
21803        position: text::Anchor,
21804        cx: &mut App,
21805    ) -> Option<Task<Vec<project::Hover>>> {
21806        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21807    }
21808
21809    fn document_highlights(
21810        &self,
21811        buffer: &Entity<Buffer>,
21812        position: text::Anchor,
21813        cx: &mut App,
21814    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21815        Some(self.update(cx, |project, cx| {
21816            project.document_highlights(buffer, position, cx)
21817        }))
21818    }
21819
21820    fn definitions(
21821        &self,
21822        buffer: &Entity<Buffer>,
21823        position: text::Anchor,
21824        kind: GotoDefinitionKind,
21825        cx: &mut App,
21826    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21827        Some(self.update(cx, |project, cx| match kind {
21828            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21829            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21830            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21831            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21832        }))
21833    }
21834
21835    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21836        // TODO: make this work for remote projects
21837        self.update(cx, |project, cx| {
21838            if project
21839                .active_debug_session(cx)
21840                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21841            {
21842                return true;
21843            }
21844
21845            buffer.update(cx, |buffer, cx| {
21846                project.any_language_server_supports_inlay_hints(buffer, cx)
21847            })
21848        })
21849    }
21850
21851    fn inline_values(
21852        &self,
21853        buffer_handle: Entity<Buffer>,
21854        range: Range<text::Anchor>,
21855        cx: &mut App,
21856    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21857        self.update(cx, |project, cx| {
21858            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21859
21860            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21861        })
21862    }
21863
21864    fn inlay_hints(
21865        &self,
21866        buffer_handle: Entity<Buffer>,
21867        range: Range<text::Anchor>,
21868        cx: &mut App,
21869    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21870        Some(self.update(cx, |project, cx| {
21871            project.inlay_hints(buffer_handle, range, cx)
21872        }))
21873    }
21874
21875    fn resolve_inlay_hint(
21876        &self,
21877        hint: InlayHint,
21878        buffer_handle: Entity<Buffer>,
21879        server_id: LanguageServerId,
21880        cx: &mut App,
21881    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21882        Some(self.update(cx, |project, cx| {
21883            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21884        }))
21885    }
21886
21887    fn range_for_rename(
21888        &self,
21889        buffer: &Entity<Buffer>,
21890        position: text::Anchor,
21891        cx: &mut App,
21892    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21893        Some(self.update(cx, |project, cx| {
21894            let buffer = buffer.clone();
21895            let task = project.prepare_rename(buffer.clone(), position, cx);
21896            cx.spawn(async move |_, cx| {
21897                Ok(match task.await? {
21898                    PrepareRenameResponse::Success(range) => Some(range),
21899                    PrepareRenameResponse::InvalidPosition => None,
21900                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21901                        // Fallback on using TreeSitter info to determine identifier range
21902                        buffer.read_with(cx, |buffer, _| {
21903                            let snapshot = buffer.snapshot();
21904                            let (range, kind) = snapshot.surrounding_word(position);
21905                            if kind != Some(CharKind::Word) {
21906                                return None;
21907                            }
21908                            Some(
21909                                snapshot.anchor_before(range.start)
21910                                    ..snapshot.anchor_after(range.end),
21911                            )
21912                        })?
21913                    }
21914                })
21915            })
21916        }))
21917    }
21918
21919    fn perform_rename(
21920        &self,
21921        buffer: &Entity<Buffer>,
21922        position: text::Anchor,
21923        new_name: String,
21924        cx: &mut App,
21925    ) -> Option<Task<Result<ProjectTransaction>>> {
21926        Some(self.update(cx, |project, cx| {
21927            project.perform_rename(buffer.clone(), position, new_name, cx)
21928        }))
21929    }
21930}
21931
21932fn inlay_hint_settings(
21933    location: Anchor,
21934    snapshot: &MultiBufferSnapshot,
21935    cx: &mut Context<Editor>,
21936) -> InlayHintSettings {
21937    let file = snapshot.file_at(location);
21938    let language = snapshot.language_at(location).map(|l| l.name());
21939    language_settings(language, file, cx).inlay_hints
21940}
21941
21942fn consume_contiguous_rows(
21943    contiguous_row_selections: &mut Vec<Selection<Point>>,
21944    selection: &Selection<Point>,
21945    display_map: &DisplaySnapshot,
21946    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21947) -> (MultiBufferRow, MultiBufferRow) {
21948    contiguous_row_selections.push(selection.clone());
21949    let start_row = MultiBufferRow(selection.start.row);
21950    let mut end_row = ending_row(selection, display_map);
21951
21952    while let Some(next_selection) = selections.peek() {
21953        if next_selection.start.row <= end_row.0 {
21954            end_row = ending_row(next_selection, display_map);
21955            contiguous_row_selections.push(selections.next().unwrap().clone());
21956        } else {
21957            break;
21958        }
21959    }
21960    (start_row, end_row)
21961}
21962
21963fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21964    if next_selection.end.column > 0 || next_selection.is_empty() {
21965        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21966    } else {
21967        MultiBufferRow(next_selection.end.row)
21968    }
21969}
21970
21971impl EditorSnapshot {
21972    pub fn remote_selections_in_range<'a>(
21973        &'a self,
21974        range: &'a Range<Anchor>,
21975        collaboration_hub: &dyn CollaborationHub,
21976        cx: &'a App,
21977    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21978        let participant_names = collaboration_hub.user_names(cx);
21979        let participant_indices = collaboration_hub.user_participant_indices(cx);
21980        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21981        let collaborators_by_replica_id = collaborators_by_peer_id
21982            .values()
21983            .map(|collaborator| (collaborator.replica_id, collaborator))
21984            .collect::<HashMap<_, _>>();
21985        self.buffer_snapshot
21986            .selections_in_range(range, false)
21987            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21988                if replica_id == AGENT_REPLICA_ID {
21989                    Some(RemoteSelection {
21990                        replica_id,
21991                        selection,
21992                        cursor_shape,
21993                        line_mode,
21994                        collaborator_id: CollaboratorId::Agent,
21995                        user_name: Some("Agent".into()),
21996                        color: cx.theme().players().agent(),
21997                    })
21998                } else {
21999                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22000                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22001                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22002                    Some(RemoteSelection {
22003                        replica_id,
22004                        selection,
22005                        cursor_shape,
22006                        line_mode,
22007                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22008                        user_name,
22009                        color: if let Some(index) = participant_index {
22010                            cx.theme().players().color_for_participant(index.0)
22011                        } else {
22012                            cx.theme().players().absent()
22013                        },
22014                    })
22015                }
22016            })
22017    }
22018
22019    pub fn hunks_for_ranges(
22020        &self,
22021        ranges: impl IntoIterator<Item = Range<Point>>,
22022    ) -> Vec<MultiBufferDiffHunk> {
22023        let mut hunks = Vec::new();
22024        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22025            HashMap::default();
22026        for query_range in ranges {
22027            let query_rows =
22028                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22029            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22030                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22031            ) {
22032                // Include deleted hunks that are adjacent to the query range, because
22033                // otherwise they would be missed.
22034                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22035                if hunk.status().is_deleted() {
22036                    intersects_range |= hunk.row_range.start == query_rows.end;
22037                    intersects_range |= hunk.row_range.end == query_rows.start;
22038                }
22039                if intersects_range {
22040                    if !processed_buffer_rows
22041                        .entry(hunk.buffer_id)
22042                        .or_default()
22043                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22044                    {
22045                        continue;
22046                    }
22047                    hunks.push(hunk);
22048                }
22049            }
22050        }
22051
22052        hunks
22053    }
22054
22055    fn display_diff_hunks_for_rows<'a>(
22056        &'a self,
22057        display_rows: Range<DisplayRow>,
22058        folded_buffers: &'a HashSet<BufferId>,
22059    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22060        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22061        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22062
22063        self.buffer_snapshot
22064            .diff_hunks_in_range(buffer_start..buffer_end)
22065            .filter_map(|hunk| {
22066                if folded_buffers.contains(&hunk.buffer_id) {
22067                    return None;
22068                }
22069
22070                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22071                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22072
22073                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22074                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22075
22076                let display_hunk = if hunk_display_start.column() != 0 {
22077                    DisplayDiffHunk::Folded {
22078                        display_row: hunk_display_start.row(),
22079                    }
22080                } else {
22081                    let mut end_row = hunk_display_end.row();
22082                    if hunk_display_end.column() > 0 {
22083                        end_row.0 += 1;
22084                    }
22085                    let is_created_file = hunk.is_created_file();
22086                    DisplayDiffHunk::Unfolded {
22087                        status: hunk.status(),
22088                        diff_base_byte_range: hunk.diff_base_byte_range,
22089                        display_row_range: hunk_display_start.row()..end_row,
22090                        multi_buffer_range: Anchor::range_in_buffer(
22091                            hunk.excerpt_id,
22092                            hunk.buffer_id,
22093                            hunk.buffer_range,
22094                        ),
22095                        is_created_file,
22096                    }
22097                };
22098
22099                Some(display_hunk)
22100            })
22101    }
22102
22103    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22104        self.display_snapshot.buffer_snapshot.language_at(position)
22105    }
22106
22107    pub fn is_focused(&self) -> bool {
22108        self.is_focused
22109    }
22110
22111    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22112        self.placeholder_text.as_ref()
22113    }
22114
22115    pub fn scroll_position(&self) -> gpui::Point<f32> {
22116        self.scroll_anchor.scroll_position(&self.display_snapshot)
22117    }
22118
22119    fn gutter_dimensions(
22120        &self,
22121        font_id: FontId,
22122        font_size: Pixels,
22123        max_line_number_width: Pixels,
22124        cx: &App,
22125    ) -> Option<GutterDimensions> {
22126        if !self.show_gutter {
22127            return None;
22128        }
22129
22130        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22131        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22132
22133        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22134            matches!(
22135                ProjectSettings::get_global(cx).git.git_gutter,
22136                Some(GitGutterSetting::TrackedFiles)
22137            )
22138        });
22139        let gutter_settings = EditorSettings::get_global(cx).gutter;
22140        let show_line_numbers = self
22141            .show_line_numbers
22142            .unwrap_or(gutter_settings.line_numbers);
22143        let line_gutter_width = if show_line_numbers {
22144            // Avoid flicker-like gutter resizes when the line number gains another digit by
22145            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22146            let min_width_for_number_on_gutter =
22147                ch_advance * gutter_settings.min_line_number_digits as f32;
22148            max_line_number_width.max(min_width_for_number_on_gutter)
22149        } else {
22150            0.0.into()
22151        };
22152
22153        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22154        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22155
22156        let git_blame_entries_width =
22157            self.git_blame_gutter_max_author_length
22158                .map(|max_author_length| {
22159                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22160                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22161
22162                    /// The number of characters to dedicate to gaps and margins.
22163                    const SPACING_WIDTH: usize = 4;
22164
22165                    let max_char_count = max_author_length.min(renderer.max_author_length())
22166                        + ::git::SHORT_SHA_LENGTH
22167                        + MAX_RELATIVE_TIMESTAMP.len()
22168                        + SPACING_WIDTH;
22169
22170                    ch_advance * max_char_count
22171                });
22172
22173        let is_singleton = self.buffer_snapshot.is_singleton();
22174
22175        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22176        left_padding += if !is_singleton {
22177            ch_width * 4.0
22178        } else if show_runnables || show_breakpoints {
22179            ch_width * 3.0
22180        } else if show_git_gutter && show_line_numbers {
22181            ch_width * 2.0
22182        } else if show_git_gutter || show_line_numbers {
22183            ch_width
22184        } else {
22185            px(0.)
22186        };
22187
22188        let shows_folds = is_singleton && gutter_settings.folds;
22189
22190        let right_padding = if shows_folds && show_line_numbers {
22191            ch_width * 4.0
22192        } else if shows_folds || (!is_singleton && show_line_numbers) {
22193            ch_width * 3.0
22194        } else if show_line_numbers {
22195            ch_width
22196        } else {
22197            px(0.)
22198        };
22199
22200        Some(GutterDimensions {
22201            left_padding,
22202            right_padding,
22203            width: line_gutter_width + left_padding + right_padding,
22204            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22205            git_blame_entries_width,
22206        })
22207    }
22208
22209    pub fn render_crease_toggle(
22210        &self,
22211        buffer_row: MultiBufferRow,
22212        row_contains_cursor: bool,
22213        editor: Entity<Editor>,
22214        window: &mut Window,
22215        cx: &mut App,
22216    ) -> Option<AnyElement> {
22217        let folded = self.is_line_folded(buffer_row);
22218        let mut is_foldable = false;
22219
22220        if let Some(crease) = self
22221            .crease_snapshot
22222            .query_row(buffer_row, &self.buffer_snapshot)
22223        {
22224            is_foldable = true;
22225            match crease {
22226                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22227                    if let Some(render_toggle) = render_toggle {
22228                        let toggle_callback =
22229                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22230                                if folded {
22231                                    editor.update(cx, |editor, cx| {
22232                                        editor.fold_at(buffer_row, window, cx)
22233                                    });
22234                                } else {
22235                                    editor.update(cx, |editor, cx| {
22236                                        editor.unfold_at(buffer_row, window, cx)
22237                                    });
22238                                }
22239                            });
22240                        return Some((render_toggle)(
22241                            buffer_row,
22242                            folded,
22243                            toggle_callback,
22244                            window,
22245                            cx,
22246                        ));
22247                    }
22248                }
22249            }
22250        }
22251
22252        is_foldable |= self.starts_indent(buffer_row);
22253
22254        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22255            Some(
22256                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22257                    .toggle_state(folded)
22258                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22259                        if folded {
22260                            this.unfold_at(buffer_row, window, cx);
22261                        } else {
22262                            this.fold_at(buffer_row, window, cx);
22263                        }
22264                    }))
22265                    .into_any_element(),
22266            )
22267        } else {
22268            None
22269        }
22270    }
22271
22272    pub fn render_crease_trailer(
22273        &self,
22274        buffer_row: MultiBufferRow,
22275        window: &mut Window,
22276        cx: &mut App,
22277    ) -> Option<AnyElement> {
22278        let folded = self.is_line_folded(buffer_row);
22279        if let Crease::Inline { render_trailer, .. } = self
22280            .crease_snapshot
22281            .query_row(buffer_row, &self.buffer_snapshot)?
22282        {
22283            let render_trailer = render_trailer.as_ref()?;
22284            Some(render_trailer(buffer_row, folded, window, cx))
22285        } else {
22286            None
22287        }
22288    }
22289}
22290
22291impl Deref for EditorSnapshot {
22292    type Target = DisplaySnapshot;
22293
22294    fn deref(&self) -> &Self::Target {
22295        &self.display_snapshot
22296    }
22297}
22298
22299#[derive(Clone, Debug, PartialEq, Eq)]
22300pub enum EditorEvent {
22301    InputIgnored {
22302        text: Arc<str>,
22303    },
22304    InputHandled {
22305        utf16_range_to_replace: Option<Range<isize>>,
22306        text: Arc<str>,
22307    },
22308    ExcerptsAdded {
22309        buffer: Entity<Buffer>,
22310        predecessor: ExcerptId,
22311        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22312    },
22313    ExcerptsRemoved {
22314        ids: Vec<ExcerptId>,
22315        removed_buffer_ids: Vec<BufferId>,
22316    },
22317    BufferFoldToggled {
22318        ids: Vec<ExcerptId>,
22319        folded: bool,
22320    },
22321    ExcerptsEdited {
22322        ids: Vec<ExcerptId>,
22323    },
22324    ExcerptsExpanded {
22325        ids: Vec<ExcerptId>,
22326    },
22327    BufferEdited,
22328    Edited {
22329        transaction_id: clock::Lamport,
22330    },
22331    Reparsed(BufferId),
22332    Focused,
22333    FocusedIn,
22334    Blurred,
22335    DirtyChanged,
22336    Saved,
22337    TitleChanged,
22338    DiffBaseChanged,
22339    SelectionsChanged {
22340        local: bool,
22341    },
22342    ScrollPositionChanged {
22343        local: bool,
22344        autoscroll: bool,
22345    },
22346    Closed,
22347    TransactionUndone {
22348        transaction_id: clock::Lamport,
22349    },
22350    TransactionBegun {
22351        transaction_id: clock::Lamport,
22352    },
22353    Reloaded,
22354    CursorShapeChanged,
22355    PushedToNavHistory {
22356        anchor: Anchor,
22357        is_deactivate: bool,
22358    },
22359}
22360
22361impl EventEmitter<EditorEvent> for Editor {}
22362
22363impl Focusable for Editor {
22364    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22365        self.focus_handle.clone()
22366    }
22367}
22368
22369impl Render for Editor {
22370    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22371        let settings = ThemeSettings::get_global(cx);
22372
22373        let mut text_style = match self.mode {
22374            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22375                color: cx.theme().colors().editor_foreground,
22376                font_family: settings.ui_font.family.clone(),
22377                font_features: settings.ui_font.features.clone(),
22378                font_fallbacks: settings.ui_font.fallbacks.clone(),
22379                font_size: rems(0.875).into(),
22380                font_weight: settings.ui_font.weight,
22381                line_height: relative(settings.buffer_line_height.value()),
22382                ..Default::default()
22383            },
22384            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22385                color: cx.theme().colors().editor_foreground,
22386                font_family: settings.buffer_font.family.clone(),
22387                font_features: settings.buffer_font.features.clone(),
22388                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22389                font_size: settings.buffer_font_size(cx).into(),
22390                font_weight: settings.buffer_font.weight,
22391                line_height: relative(settings.buffer_line_height.value()),
22392                ..Default::default()
22393            },
22394        };
22395        if let Some(text_style_refinement) = &self.text_style_refinement {
22396            text_style.refine(text_style_refinement)
22397        }
22398
22399        let background = match self.mode {
22400            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22401            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22402            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22403            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22404        };
22405
22406        EditorElement::new(
22407            &cx.entity(),
22408            EditorStyle {
22409                background,
22410                border: cx.theme().colors().border,
22411                local_player: cx.theme().players().local(),
22412                text: text_style,
22413                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22414                syntax: cx.theme().syntax().clone(),
22415                status: cx.theme().status().clone(),
22416                inlay_hints_style: make_inlay_hints_style(cx),
22417                inline_completion_styles: make_suggestion_styles(cx),
22418                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22419                show_underlines: self.diagnostics_enabled(),
22420            },
22421        )
22422    }
22423}
22424
22425impl EntityInputHandler for Editor {
22426    fn text_for_range(
22427        &mut self,
22428        range_utf16: Range<usize>,
22429        adjusted_range: &mut Option<Range<usize>>,
22430        _: &mut Window,
22431        cx: &mut Context<Self>,
22432    ) -> Option<String> {
22433        let snapshot = self.buffer.read(cx).read(cx);
22434        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22435        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22436        if (start.0..end.0) != range_utf16 {
22437            adjusted_range.replace(start.0..end.0);
22438        }
22439        Some(snapshot.text_for_range(start..end).collect())
22440    }
22441
22442    fn selected_text_range(
22443        &mut self,
22444        ignore_disabled_input: bool,
22445        _: &mut Window,
22446        cx: &mut Context<Self>,
22447    ) -> Option<UTF16Selection> {
22448        // Prevent the IME menu from appearing when holding down an alphabetic key
22449        // while input is disabled.
22450        if !ignore_disabled_input && !self.input_enabled {
22451            return None;
22452        }
22453
22454        let selection = self.selections.newest::<OffsetUtf16>(cx);
22455        let range = selection.range();
22456
22457        Some(UTF16Selection {
22458            range: range.start.0..range.end.0,
22459            reversed: selection.reversed,
22460        })
22461    }
22462
22463    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22464        let snapshot = self.buffer.read(cx).read(cx);
22465        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22466        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22467    }
22468
22469    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22470        self.clear_highlights::<InputComposition>(cx);
22471        self.ime_transaction.take();
22472    }
22473
22474    fn replace_text_in_range(
22475        &mut self,
22476        range_utf16: Option<Range<usize>>,
22477        text: &str,
22478        window: &mut Window,
22479        cx: &mut Context<Self>,
22480    ) {
22481        if !self.input_enabled {
22482            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22483            return;
22484        }
22485
22486        self.transact(window, cx, |this, window, cx| {
22487            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22488                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22489                Some(this.selection_replacement_ranges(range_utf16, cx))
22490            } else {
22491                this.marked_text_ranges(cx)
22492            };
22493
22494            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22495                let newest_selection_id = this.selections.newest_anchor().id;
22496                this.selections
22497                    .all::<OffsetUtf16>(cx)
22498                    .iter()
22499                    .zip(ranges_to_replace.iter())
22500                    .find_map(|(selection, range)| {
22501                        if selection.id == newest_selection_id {
22502                            Some(
22503                                (range.start.0 as isize - selection.head().0 as isize)
22504                                    ..(range.end.0 as isize - selection.head().0 as isize),
22505                            )
22506                        } else {
22507                            None
22508                        }
22509                    })
22510            });
22511
22512            cx.emit(EditorEvent::InputHandled {
22513                utf16_range_to_replace: range_to_replace,
22514                text: text.into(),
22515            });
22516
22517            if let Some(new_selected_ranges) = new_selected_ranges {
22518                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22519                    selections.select_ranges(new_selected_ranges)
22520                });
22521                this.backspace(&Default::default(), window, cx);
22522            }
22523
22524            this.handle_input(text, window, cx);
22525        });
22526
22527        if let Some(transaction) = self.ime_transaction {
22528            self.buffer.update(cx, |buffer, cx| {
22529                buffer.group_until_transaction(transaction, cx);
22530            });
22531        }
22532
22533        self.unmark_text(window, cx);
22534    }
22535
22536    fn replace_and_mark_text_in_range(
22537        &mut self,
22538        range_utf16: Option<Range<usize>>,
22539        text: &str,
22540        new_selected_range_utf16: Option<Range<usize>>,
22541        window: &mut Window,
22542        cx: &mut Context<Self>,
22543    ) {
22544        if !self.input_enabled {
22545            return;
22546        }
22547
22548        let transaction = self.transact(window, cx, |this, window, cx| {
22549            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22550                let snapshot = this.buffer.read(cx).read(cx);
22551                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22552                    for marked_range in &mut marked_ranges {
22553                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22554                        marked_range.start.0 += relative_range_utf16.start;
22555                        marked_range.start =
22556                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22557                        marked_range.end =
22558                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22559                    }
22560                }
22561                Some(marked_ranges)
22562            } else if let Some(range_utf16) = range_utf16 {
22563                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22564                Some(this.selection_replacement_ranges(range_utf16, cx))
22565            } else {
22566                None
22567            };
22568
22569            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22570                let newest_selection_id = this.selections.newest_anchor().id;
22571                this.selections
22572                    .all::<OffsetUtf16>(cx)
22573                    .iter()
22574                    .zip(ranges_to_replace.iter())
22575                    .find_map(|(selection, range)| {
22576                        if selection.id == newest_selection_id {
22577                            Some(
22578                                (range.start.0 as isize - selection.head().0 as isize)
22579                                    ..(range.end.0 as isize - selection.head().0 as isize),
22580                            )
22581                        } else {
22582                            None
22583                        }
22584                    })
22585            });
22586
22587            cx.emit(EditorEvent::InputHandled {
22588                utf16_range_to_replace: range_to_replace,
22589                text: text.into(),
22590            });
22591
22592            if let Some(ranges) = ranges_to_replace {
22593                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22594                    s.select_ranges(ranges)
22595                });
22596            }
22597
22598            let marked_ranges = {
22599                let snapshot = this.buffer.read(cx).read(cx);
22600                this.selections
22601                    .disjoint_anchors()
22602                    .iter()
22603                    .map(|selection| {
22604                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22605                    })
22606                    .collect::<Vec<_>>()
22607            };
22608
22609            if text.is_empty() {
22610                this.unmark_text(window, cx);
22611            } else {
22612                this.highlight_text::<InputComposition>(
22613                    marked_ranges.clone(),
22614                    HighlightStyle {
22615                        underline: Some(UnderlineStyle {
22616                            thickness: px(1.),
22617                            color: None,
22618                            wavy: false,
22619                        }),
22620                        ..Default::default()
22621                    },
22622                    cx,
22623                );
22624            }
22625
22626            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22627            let use_autoclose = this.use_autoclose;
22628            let use_auto_surround = this.use_auto_surround;
22629            this.set_use_autoclose(false);
22630            this.set_use_auto_surround(false);
22631            this.handle_input(text, window, cx);
22632            this.set_use_autoclose(use_autoclose);
22633            this.set_use_auto_surround(use_auto_surround);
22634
22635            if let Some(new_selected_range) = new_selected_range_utf16 {
22636                let snapshot = this.buffer.read(cx).read(cx);
22637                let new_selected_ranges = marked_ranges
22638                    .into_iter()
22639                    .map(|marked_range| {
22640                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22641                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22642                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22643                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22644                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22645                    })
22646                    .collect::<Vec<_>>();
22647
22648                drop(snapshot);
22649                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22650                    selections.select_ranges(new_selected_ranges)
22651                });
22652            }
22653        });
22654
22655        self.ime_transaction = self.ime_transaction.or(transaction);
22656        if let Some(transaction) = self.ime_transaction {
22657            self.buffer.update(cx, |buffer, cx| {
22658                buffer.group_until_transaction(transaction, cx);
22659            });
22660        }
22661
22662        if self.text_highlights::<InputComposition>(cx).is_none() {
22663            self.ime_transaction.take();
22664        }
22665    }
22666
22667    fn bounds_for_range(
22668        &mut self,
22669        range_utf16: Range<usize>,
22670        element_bounds: gpui::Bounds<Pixels>,
22671        window: &mut Window,
22672        cx: &mut Context<Self>,
22673    ) -> Option<gpui::Bounds<Pixels>> {
22674        let text_layout_details = self.text_layout_details(window);
22675        let CharacterDimensions {
22676            em_width,
22677            em_advance,
22678            line_height,
22679        } = self.character_dimensions(window);
22680
22681        let snapshot = self.snapshot(window, cx);
22682        let scroll_position = snapshot.scroll_position();
22683        let scroll_left = scroll_position.x * em_advance;
22684
22685        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22686        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22687            + self.gutter_dimensions.full_width();
22688        let y = line_height * (start.row().as_f32() - scroll_position.y);
22689
22690        Some(Bounds {
22691            origin: element_bounds.origin + point(x, y),
22692            size: size(em_width, line_height),
22693        })
22694    }
22695
22696    fn character_index_for_point(
22697        &mut self,
22698        point: gpui::Point<Pixels>,
22699        _window: &mut Window,
22700        _cx: &mut Context<Self>,
22701    ) -> Option<usize> {
22702        let position_map = self.last_position_map.as_ref()?;
22703        if !position_map.text_hitbox.contains(&point) {
22704            return None;
22705        }
22706        let display_point = position_map.point_for_position(point).previous_valid;
22707        let anchor = position_map
22708            .snapshot
22709            .display_point_to_anchor(display_point, Bias::Left);
22710        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22711        Some(utf16_offset.0)
22712    }
22713}
22714
22715trait SelectionExt {
22716    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22717    fn spanned_rows(
22718        &self,
22719        include_end_if_at_line_start: bool,
22720        map: &DisplaySnapshot,
22721    ) -> Range<MultiBufferRow>;
22722}
22723
22724impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22725    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22726        let start = self
22727            .start
22728            .to_point(&map.buffer_snapshot)
22729            .to_display_point(map);
22730        let end = self
22731            .end
22732            .to_point(&map.buffer_snapshot)
22733            .to_display_point(map);
22734        if self.reversed {
22735            end..start
22736        } else {
22737            start..end
22738        }
22739    }
22740
22741    fn spanned_rows(
22742        &self,
22743        include_end_if_at_line_start: bool,
22744        map: &DisplaySnapshot,
22745    ) -> Range<MultiBufferRow> {
22746        let start = self.start.to_point(&map.buffer_snapshot);
22747        let mut end = self.end.to_point(&map.buffer_snapshot);
22748        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22749            end.row -= 1;
22750        }
22751
22752        let buffer_start = map.prev_line_boundary(start).0;
22753        let buffer_end = map.next_line_boundary(end).0;
22754        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22755    }
22756}
22757
22758impl<T: InvalidationRegion> InvalidationStack<T> {
22759    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22760    where
22761        S: Clone + ToOffset,
22762    {
22763        while let Some(region) = self.last() {
22764            let all_selections_inside_invalidation_ranges =
22765                if selections.len() == region.ranges().len() {
22766                    selections
22767                        .iter()
22768                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22769                        .all(|(selection, invalidation_range)| {
22770                            let head = selection.head().to_offset(buffer);
22771                            invalidation_range.start <= head && invalidation_range.end >= head
22772                        })
22773                } else {
22774                    false
22775                };
22776
22777            if all_selections_inside_invalidation_ranges {
22778                break;
22779            } else {
22780                self.pop();
22781            }
22782        }
22783    }
22784}
22785
22786impl<T> Default for InvalidationStack<T> {
22787    fn default() -> Self {
22788        Self(Default::default())
22789    }
22790}
22791
22792impl<T> Deref for InvalidationStack<T> {
22793    type Target = Vec<T>;
22794
22795    fn deref(&self) -> &Self::Target {
22796        &self.0
22797    }
22798}
22799
22800impl<T> DerefMut for InvalidationStack<T> {
22801    fn deref_mut(&mut self) -> &mut Self::Target {
22802        &mut self.0
22803    }
22804}
22805
22806impl InvalidationRegion for SnippetState {
22807    fn ranges(&self) -> &[Range<Anchor>] {
22808        &self.ranges[self.active_index]
22809    }
22810}
22811
22812fn inline_completion_edit_text(
22813    current_snapshot: &BufferSnapshot,
22814    edits: &[(Range<Anchor>, String)],
22815    edit_preview: &EditPreview,
22816    include_deletions: bool,
22817    cx: &App,
22818) -> HighlightedText {
22819    let edits = edits
22820        .iter()
22821        .map(|(anchor, text)| {
22822            (
22823                anchor.start.text_anchor..anchor.end.text_anchor,
22824                text.clone(),
22825            )
22826        })
22827        .collect::<Vec<_>>();
22828
22829    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22830}
22831
22832pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22833    match severity {
22834        lsp::DiagnosticSeverity::ERROR => colors.error,
22835        lsp::DiagnosticSeverity::WARNING => colors.warning,
22836        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22837        lsp::DiagnosticSeverity::HINT => colors.info,
22838        _ => colors.ignored,
22839    }
22840}
22841
22842pub fn styled_runs_for_code_label<'a>(
22843    label: &'a CodeLabel,
22844    syntax_theme: &'a theme::SyntaxTheme,
22845) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22846    let fade_out = HighlightStyle {
22847        fade_out: Some(0.35),
22848        ..Default::default()
22849    };
22850
22851    let mut prev_end = label.filter_range.end;
22852    label
22853        .runs
22854        .iter()
22855        .enumerate()
22856        .flat_map(move |(ix, (range, highlight_id))| {
22857            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22858                style
22859            } else {
22860                return Default::default();
22861            };
22862            let mut muted_style = style;
22863            muted_style.highlight(fade_out);
22864
22865            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22866            if range.start >= label.filter_range.end {
22867                if range.start > prev_end {
22868                    runs.push((prev_end..range.start, fade_out));
22869                }
22870                runs.push((range.clone(), muted_style));
22871            } else if range.end <= label.filter_range.end {
22872                runs.push((range.clone(), style));
22873            } else {
22874                runs.push((range.start..label.filter_range.end, style));
22875                runs.push((label.filter_range.end..range.end, muted_style));
22876            }
22877            prev_end = cmp::max(prev_end, range.end);
22878
22879            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22880                runs.push((prev_end..label.text.len(), fade_out));
22881            }
22882
22883            runs
22884        })
22885}
22886
22887pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22888    let mut prev_index = 0;
22889    let mut prev_codepoint: Option<char> = None;
22890    text.char_indices()
22891        .chain([(text.len(), '\0')])
22892        .filter_map(move |(index, codepoint)| {
22893            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22894            let is_boundary = index == text.len()
22895                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22896                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22897            if is_boundary {
22898                let chunk = &text[prev_index..index];
22899                prev_index = index;
22900                Some(chunk)
22901            } else {
22902                None
22903            }
22904        })
22905}
22906
22907pub trait RangeToAnchorExt: Sized {
22908    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22909
22910    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22911        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22912        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22913    }
22914}
22915
22916impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22917    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22918        let start_offset = self.start.to_offset(snapshot);
22919        let end_offset = self.end.to_offset(snapshot);
22920        if start_offset == end_offset {
22921            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22922        } else {
22923            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22924        }
22925    }
22926}
22927
22928pub trait RowExt {
22929    fn as_f32(&self) -> f32;
22930
22931    fn next_row(&self) -> Self;
22932
22933    fn previous_row(&self) -> Self;
22934
22935    fn minus(&self, other: Self) -> u32;
22936}
22937
22938impl RowExt for DisplayRow {
22939    fn as_f32(&self) -> f32 {
22940        self.0 as f32
22941    }
22942
22943    fn next_row(&self) -> Self {
22944        Self(self.0 + 1)
22945    }
22946
22947    fn previous_row(&self) -> Self {
22948        Self(self.0.saturating_sub(1))
22949    }
22950
22951    fn minus(&self, other: Self) -> u32 {
22952        self.0 - other.0
22953    }
22954}
22955
22956impl RowExt for MultiBufferRow {
22957    fn as_f32(&self) -> f32 {
22958        self.0 as f32
22959    }
22960
22961    fn next_row(&self) -> Self {
22962        Self(self.0 + 1)
22963    }
22964
22965    fn previous_row(&self) -> Self {
22966        Self(self.0.saturating_sub(1))
22967    }
22968
22969    fn minus(&self, other: Self) -> u32 {
22970        self.0 - other.0
22971    }
22972}
22973
22974trait RowRangeExt {
22975    type Row;
22976
22977    fn len(&self) -> usize;
22978
22979    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22980}
22981
22982impl RowRangeExt for Range<MultiBufferRow> {
22983    type Row = MultiBufferRow;
22984
22985    fn len(&self) -> usize {
22986        (self.end.0 - self.start.0) as usize
22987    }
22988
22989    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22990        (self.start.0..self.end.0).map(MultiBufferRow)
22991    }
22992}
22993
22994impl RowRangeExt for Range<DisplayRow> {
22995    type Row = DisplayRow;
22996
22997    fn len(&self) -> usize {
22998        (self.end.0 - self.start.0) as usize
22999    }
23000
23001    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23002        (self.start.0..self.end.0).map(DisplayRow)
23003    }
23004}
23005
23006/// If select range has more than one line, we
23007/// just point the cursor to range.start.
23008fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23009    if range.start.row == range.end.row {
23010        range
23011    } else {
23012        range.start..range.start
23013    }
23014}
23015pub struct KillRing(ClipboardItem);
23016impl Global for KillRing {}
23017
23018const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23019
23020enum BreakpointPromptEditAction {
23021    Log,
23022    Condition,
23023    HitCondition,
23024}
23025
23026struct BreakpointPromptEditor {
23027    pub(crate) prompt: Entity<Editor>,
23028    editor: WeakEntity<Editor>,
23029    breakpoint_anchor: Anchor,
23030    breakpoint: Breakpoint,
23031    edit_action: BreakpointPromptEditAction,
23032    block_ids: HashSet<CustomBlockId>,
23033    editor_margins: Arc<Mutex<EditorMargins>>,
23034    _subscriptions: Vec<Subscription>,
23035}
23036
23037impl BreakpointPromptEditor {
23038    const MAX_LINES: u8 = 4;
23039
23040    fn new(
23041        editor: WeakEntity<Editor>,
23042        breakpoint_anchor: Anchor,
23043        breakpoint: Breakpoint,
23044        edit_action: BreakpointPromptEditAction,
23045        window: &mut Window,
23046        cx: &mut Context<Self>,
23047    ) -> Self {
23048        let base_text = match edit_action {
23049            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23050            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23051            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23052        }
23053        .map(|msg| msg.to_string())
23054        .unwrap_or_default();
23055
23056        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23057        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23058
23059        let prompt = cx.new(|cx| {
23060            let mut prompt = Editor::new(
23061                EditorMode::AutoHeight {
23062                    min_lines: 1,
23063                    max_lines: Some(Self::MAX_LINES as usize),
23064                },
23065                buffer,
23066                None,
23067                window,
23068                cx,
23069            );
23070            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23071            prompt.set_show_cursor_when_unfocused(false, cx);
23072            prompt.set_placeholder_text(
23073                match edit_action {
23074                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23075                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23076                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23077                },
23078                cx,
23079            );
23080
23081            prompt
23082        });
23083
23084        Self {
23085            prompt,
23086            editor,
23087            breakpoint_anchor,
23088            breakpoint,
23089            edit_action,
23090            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23091            block_ids: Default::default(),
23092            _subscriptions: vec![],
23093        }
23094    }
23095
23096    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23097        self.block_ids.extend(block_ids)
23098    }
23099
23100    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23101        if let Some(editor) = self.editor.upgrade() {
23102            let message = self
23103                .prompt
23104                .read(cx)
23105                .buffer
23106                .read(cx)
23107                .as_singleton()
23108                .expect("A multi buffer in breakpoint prompt isn't possible")
23109                .read(cx)
23110                .as_rope()
23111                .to_string();
23112
23113            editor.update(cx, |editor, cx| {
23114                editor.edit_breakpoint_at_anchor(
23115                    self.breakpoint_anchor,
23116                    self.breakpoint.clone(),
23117                    match self.edit_action {
23118                        BreakpointPromptEditAction::Log => {
23119                            BreakpointEditAction::EditLogMessage(message.into())
23120                        }
23121                        BreakpointPromptEditAction::Condition => {
23122                            BreakpointEditAction::EditCondition(message.into())
23123                        }
23124                        BreakpointPromptEditAction::HitCondition => {
23125                            BreakpointEditAction::EditHitCondition(message.into())
23126                        }
23127                    },
23128                    cx,
23129                );
23130
23131                editor.remove_blocks(self.block_ids.clone(), None, cx);
23132                cx.focus_self(window);
23133            });
23134        }
23135    }
23136
23137    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23138        self.editor
23139            .update(cx, |editor, cx| {
23140                editor.remove_blocks(self.block_ids.clone(), None, cx);
23141                window.focus(&editor.focus_handle);
23142            })
23143            .log_err();
23144    }
23145
23146    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23147        let settings = ThemeSettings::get_global(cx);
23148        let text_style = TextStyle {
23149            color: if self.prompt.read(cx).read_only(cx) {
23150                cx.theme().colors().text_disabled
23151            } else {
23152                cx.theme().colors().text
23153            },
23154            font_family: settings.buffer_font.family.clone(),
23155            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23156            font_size: settings.buffer_font_size(cx).into(),
23157            font_weight: settings.buffer_font.weight,
23158            line_height: relative(settings.buffer_line_height.value()),
23159            ..Default::default()
23160        };
23161        EditorElement::new(
23162            &self.prompt,
23163            EditorStyle {
23164                background: cx.theme().colors().editor_background,
23165                local_player: cx.theme().players().local(),
23166                text: text_style,
23167                ..Default::default()
23168            },
23169        )
23170    }
23171}
23172
23173impl Render for BreakpointPromptEditor {
23174    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23175        let editor_margins = *self.editor_margins.lock();
23176        let gutter_dimensions = editor_margins.gutter;
23177        h_flex()
23178            .key_context("Editor")
23179            .bg(cx.theme().colors().editor_background)
23180            .border_y_1()
23181            .border_color(cx.theme().status().info_border)
23182            .size_full()
23183            .py(window.line_height() / 2.5)
23184            .on_action(cx.listener(Self::confirm))
23185            .on_action(cx.listener(Self::cancel))
23186            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23187            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23188    }
23189}
23190
23191impl Focusable for BreakpointPromptEditor {
23192    fn focus_handle(&self, cx: &App) -> FocusHandle {
23193        self.prompt.focus_handle(cx)
23194    }
23195}
23196
23197fn all_edits_insertions_or_deletions(
23198    edits: &Vec<(Range<Anchor>, String)>,
23199    snapshot: &MultiBufferSnapshot,
23200) -> bool {
23201    let mut all_insertions = true;
23202    let mut all_deletions = true;
23203
23204    for (range, new_text) in edits.iter() {
23205        let range_is_empty = range.to_offset(&snapshot).is_empty();
23206        let text_is_empty = new_text.is_empty();
23207
23208        if range_is_empty != text_is_empty {
23209            if range_is_empty {
23210                all_deletions = false;
23211            } else {
23212                all_insertions = false;
23213            }
23214        } else {
23215            return false;
23216        }
23217
23218        if !all_insertions && !all_deletions {
23219            return false;
23220        }
23221    }
23222    all_insertions || all_deletions
23223}
23224
23225struct MissingEditPredictionKeybindingTooltip;
23226
23227impl Render for MissingEditPredictionKeybindingTooltip {
23228    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23229        ui::tooltip_container(window, cx, |container, _, cx| {
23230            container
23231                .flex_shrink_0()
23232                .max_w_80()
23233                .min_h(rems_from_px(124.))
23234                .justify_between()
23235                .child(
23236                    v_flex()
23237                        .flex_1()
23238                        .text_ui_sm(cx)
23239                        .child(Label::new("Conflict with Accept Keybinding"))
23240                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23241                )
23242                .child(
23243                    h_flex()
23244                        .pb_1()
23245                        .gap_1()
23246                        .items_end()
23247                        .w_full()
23248                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23249                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23250                        }))
23251                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23252                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23253                        })),
23254                )
23255        })
23256    }
23257}
23258
23259#[derive(Debug, Clone, Copy, PartialEq)]
23260pub struct LineHighlight {
23261    pub background: Background,
23262    pub border: Option<gpui::Hsla>,
23263    pub include_gutter: bool,
23264    pub type_id: Option<TypeId>,
23265}
23266
23267struct LineManipulationResult {
23268    pub new_text: String,
23269    pub line_count_before: usize,
23270    pub line_count_after: usize,
23271}
23272
23273fn render_diff_hunk_controls(
23274    row: u32,
23275    status: &DiffHunkStatus,
23276    hunk_range: Range<Anchor>,
23277    is_created_file: bool,
23278    line_height: Pixels,
23279    editor: &Entity<Editor>,
23280    _window: &mut Window,
23281    cx: &mut App,
23282) -> AnyElement {
23283    h_flex()
23284        .h(line_height)
23285        .mr_1()
23286        .gap_1()
23287        .px_0p5()
23288        .pb_1()
23289        .border_x_1()
23290        .border_b_1()
23291        .border_color(cx.theme().colors().border_variant)
23292        .rounded_b_lg()
23293        .bg(cx.theme().colors().editor_background)
23294        .gap_1()
23295        .block_mouse_except_scroll()
23296        .shadow_md()
23297        .child(if status.has_secondary_hunk() {
23298            Button::new(("stage", row as u64), "Stage")
23299                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23300                .tooltip({
23301                    let focus_handle = editor.focus_handle(cx);
23302                    move |window, cx| {
23303                        Tooltip::for_action_in(
23304                            "Stage Hunk",
23305                            &::git::ToggleStaged,
23306                            &focus_handle,
23307                            window,
23308                            cx,
23309                        )
23310                    }
23311                })
23312                .on_click({
23313                    let editor = editor.clone();
23314                    move |_event, _window, cx| {
23315                        editor.update(cx, |editor, cx| {
23316                            editor.stage_or_unstage_diff_hunks(
23317                                true,
23318                                vec![hunk_range.start..hunk_range.start],
23319                                cx,
23320                            );
23321                        });
23322                    }
23323                })
23324        } else {
23325            Button::new(("unstage", row as u64), "Unstage")
23326                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23327                .tooltip({
23328                    let focus_handle = editor.focus_handle(cx);
23329                    move |window, cx| {
23330                        Tooltip::for_action_in(
23331                            "Unstage Hunk",
23332                            &::git::ToggleStaged,
23333                            &focus_handle,
23334                            window,
23335                            cx,
23336                        )
23337                    }
23338                })
23339                .on_click({
23340                    let editor = editor.clone();
23341                    move |_event, _window, cx| {
23342                        editor.update(cx, |editor, cx| {
23343                            editor.stage_or_unstage_diff_hunks(
23344                                false,
23345                                vec![hunk_range.start..hunk_range.start],
23346                                cx,
23347                            );
23348                        });
23349                    }
23350                })
23351        })
23352        .child(
23353            Button::new(("restore", row as u64), "Restore")
23354                .tooltip({
23355                    let focus_handle = editor.focus_handle(cx);
23356                    move |window, cx| {
23357                        Tooltip::for_action_in(
23358                            "Restore Hunk",
23359                            &::git::Restore,
23360                            &focus_handle,
23361                            window,
23362                            cx,
23363                        )
23364                    }
23365                })
23366                .on_click({
23367                    let editor = editor.clone();
23368                    move |_event, window, cx| {
23369                        editor.update(cx, |editor, cx| {
23370                            let snapshot = editor.snapshot(window, cx);
23371                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23372                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23373                        });
23374                    }
23375                })
23376                .disabled(is_created_file),
23377        )
23378        .when(
23379            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23380            |el| {
23381                el.child(
23382                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23383                        .shape(IconButtonShape::Square)
23384                        .icon_size(IconSize::Small)
23385                        // .disabled(!has_multiple_hunks)
23386                        .tooltip({
23387                            let focus_handle = editor.focus_handle(cx);
23388                            move |window, cx| {
23389                                Tooltip::for_action_in(
23390                                    "Next Hunk",
23391                                    &GoToHunk,
23392                                    &focus_handle,
23393                                    window,
23394                                    cx,
23395                                )
23396                            }
23397                        })
23398                        .on_click({
23399                            let editor = editor.clone();
23400                            move |_event, window, cx| {
23401                                editor.update(cx, |editor, cx| {
23402                                    let snapshot = editor.snapshot(window, cx);
23403                                    let position =
23404                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23405                                    editor.go_to_hunk_before_or_after_position(
23406                                        &snapshot,
23407                                        position,
23408                                        Direction::Next,
23409                                        window,
23410                                        cx,
23411                                    );
23412                                    editor.expand_selected_diff_hunks(cx);
23413                                });
23414                            }
23415                        }),
23416                )
23417                .child(
23418                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23419                        .shape(IconButtonShape::Square)
23420                        .icon_size(IconSize::Small)
23421                        // .disabled(!has_multiple_hunks)
23422                        .tooltip({
23423                            let focus_handle = editor.focus_handle(cx);
23424                            move |window, cx| {
23425                                Tooltip::for_action_in(
23426                                    "Previous Hunk",
23427                                    &GoToPreviousHunk,
23428                                    &focus_handle,
23429                                    window,
23430                                    cx,
23431                                )
23432                            }
23433                        })
23434                        .on_click({
23435                            let editor = editor.clone();
23436                            move |_event, window, cx| {
23437                                editor.update(cx, |editor, cx| {
23438                                    let snapshot = editor.snapshot(window, cx);
23439                                    let point =
23440                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23441                                    editor.go_to_hunk_before_or_after_position(
23442                                        &snapshot,
23443                                        point,
23444                                        Direction::Prev,
23445                                        window,
23446                                        cx,
23447                                    );
23448                                    editor.expand_selected_diff_hunks(cx);
23449                                });
23450                            }
23451                        }),
23452                )
23453            },
23454        )
23455        .into_any_element()
23456}