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
  868struct ChangeLocation {
  869    current: Option<Vec<Anchor>>,
  870    original: Vec<Anchor>,
  871}
  872impl ChangeLocation {
  873    fn locations(&self) -> &[Anchor] {
  874        self.current.as_ref().unwrap_or(&self.original)
  875    }
  876}
  877
  878/// A set of caret positions, registered when the editor was edited.
  879pub struct ChangeList {
  880    changes: Vec<ChangeLocation>,
  881    /// Currently "selected" change.
  882    position: Option<usize>,
  883}
  884
  885impl ChangeList {
  886    pub fn new() -> Self {
  887        Self {
  888            changes: Vec::new(),
  889            position: None,
  890        }
  891    }
  892
  893    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  894    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  895    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  896        if self.changes.is_empty() {
  897            return None;
  898        }
  899
  900        let prev = self.position.unwrap_or(self.changes.len());
  901        let next = if direction == Direction::Prev {
  902            prev.saturating_sub(count)
  903        } else {
  904            (prev + count).min(self.changes.len() - 1)
  905        };
  906        self.position = Some(next);
  907        self.changes.get(next).map(|change| change.locations())
  908    }
  909
  910    /// Adds a new change to the list, resetting the change list position.
  911    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  912        self.position.take();
  913        if let Some(last) = self.changes.last_mut()
  914            && group
  915        {
  916            last.current = Some(new_positions)
  917        } else {
  918            self.changes.push(ChangeLocation {
  919                original: new_positions,
  920                current: None,
  921            });
  922        }
  923    }
  924
  925    pub fn last(&self) -> Option<&[Anchor]> {
  926        self.changes.last().map(|change| change.locations())
  927    }
  928
  929    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  930        self.changes.last().map(|change| change.original.as_slice())
  931    }
  932
  933    pub fn invert_last_group(&mut self) {
  934        if let Some(last) = self.changes.last_mut() {
  935            if let Some(current) = last.current.as_mut() {
  936                mem::swap(&mut last.original, current);
  937            }
  938        }
  939    }
  940}
  941
  942#[derive(Clone)]
  943struct InlineBlamePopoverState {
  944    scroll_handle: ScrollHandle,
  945    commit_message: Option<ParsedCommitMessage>,
  946    markdown: Entity<Markdown>,
  947}
  948
  949struct InlineBlamePopover {
  950    position: gpui::Point<Pixels>,
  951    hide_task: Option<Task<()>>,
  952    popover_bounds: Option<Bounds<Pixels>>,
  953    popover_state: InlineBlamePopoverState,
  954}
  955
  956enum SelectionDragState {
  957    /// State when no drag related activity is detected.
  958    None,
  959    /// State when the mouse is down on a selection that is about to be dragged.
  960    ReadyToDrag {
  961        selection: Selection<Anchor>,
  962        click_position: gpui::Point<Pixels>,
  963        mouse_down_time: Instant,
  964    },
  965    /// State when the mouse is dragging the selection in the editor.
  966    Dragging {
  967        selection: Selection<Anchor>,
  968        drop_cursor: Selection<Anchor>,
  969        hide_drop_cursor: bool,
  970    },
  971}
  972
  973enum ColumnarSelectionState {
  974    FromMouse {
  975        selection_tail: Anchor,
  976        display_point: Option<DisplayPoint>,
  977    },
  978    FromSelection {
  979        selection_tail: Anchor,
  980    },
  981}
  982
  983/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  984/// a breakpoint on them.
  985#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  986struct PhantomBreakpointIndicator {
  987    display_row: DisplayRow,
  988    /// There's a small debounce between hovering over the line and showing the indicator.
  989    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  990    is_active: bool,
  991    collides_with_existing_breakpoint: bool,
  992}
  993
  994/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  995///
  996/// See the [module level documentation](self) for more information.
  997pub struct Editor {
  998    focus_handle: FocusHandle,
  999    last_focused_descendant: Option<WeakFocusHandle>,
 1000    /// The text buffer being edited
 1001    buffer: Entity<MultiBuffer>,
 1002    /// Map of how text in the buffer should be displayed.
 1003    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1004    pub display_map: Entity<DisplayMap>,
 1005    pub selections: SelectionsCollection,
 1006    pub scroll_manager: ScrollManager,
 1007    /// When inline assist editors are linked, they all render cursors because
 1008    /// typing enters text into each of them, even the ones that aren't focused.
 1009    pub(crate) show_cursor_when_unfocused: bool,
 1010    columnar_selection_state: Option<ColumnarSelectionState>,
 1011    add_selections_state: Option<AddSelectionsState>,
 1012    select_next_state: Option<SelectNextState>,
 1013    select_prev_state: Option<SelectNextState>,
 1014    selection_history: SelectionHistory,
 1015    defer_selection_effects: bool,
 1016    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1017    autoclose_regions: Vec<AutocloseRegion>,
 1018    snippet_stack: InvalidationStack<SnippetState>,
 1019    select_syntax_node_history: SelectSyntaxNodeHistory,
 1020    ime_transaction: Option<TransactionId>,
 1021    pub diagnostics_max_severity: DiagnosticSeverity,
 1022    active_diagnostics: ActiveDiagnostic,
 1023    show_inline_diagnostics: bool,
 1024    inline_diagnostics_update: Task<()>,
 1025    inline_diagnostics_enabled: bool,
 1026    diagnostics_enabled: bool,
 1027    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1028    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1029    hard_wrap: Option<usize>,
 1030
 1031    // TODO: make this a access method
 1032    pub project: Option<Entity<Project>>,
 1033    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1034    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1035    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1036    blink_manager: Entity<BlinkManager>,
 1037    show_cursor_names: bool,
 1038    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1039    pub show_local_selections: bool,
 1040    mode: EditorMode,
 1041    show_breadcrumbs: bool,
 1042    show_gutter: bool,
 1043    show_scrollbars: ScrollbarAxes,
 1044    minimap_visibility: MinimapVisibility,
 1045    offset_content: bool,
 1046    disable_expand_excerpt_buttons: bool,
 1047    show_line_numbers: Option<bool>,
 1048    use_relative_line_numbers: Option<bool>,
 1049    show_git_diff_gutter: Option<bool>,
 1050    show_code_actions: Option<bool>,
 1051    show_runnables: Option<bool>,
 1052    show_breakpoints: Option<bool>,
 1053    show_wrap_guides: Option<bool>,
 1054    show_indent_guides: Option<bool>,
 1055    placeholder_text: Option<Arc<str>>,
 1056    highlight_order: usize,
 1057    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1058    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1059    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1060    scrollbar_marker_state: ScrollbarMarkerState,
 1061    active_indent_guides_state: ActiveIndentGuidesState,
 1062    nav_history: Option<ItemNavHistory>,
 1063    context_menu: RefCell<Option<CodeContextMenu>>,
 1064    context_menu_options: Option<ContextMenuOptions>,
 1065    mouse_context_menu: Option<MouseContextMenu>,
 1066    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1067    inline_blame_popover: Option<InlineBlamePopover>,
 1068    inline_blame_popover_show_task: Option<Task<()>>,
 1069    signature_help_state: SignatureHelpState,
 1070    auto_signature_help: Option<bool>,
 1071    find_all_references_task_sources: Vec<Anchor>,
 1072    next_completion_id: CompletionId,
 1073    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1074    code_actions_task: Option<Task<Result<()>>>,
 1075    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1076    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    document_highlights_task: Option<Task<()>>,
 1078    linked_editing_range_task: Option<Task<Option<()>>>,
 1079    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1080    pending_rename: Option<RenameState>,
 1081    searchable: bool,
 1082    cursor_shape: CursorShape,
 1083    current_line_highlight: Option<CurrentLineHighlight>,
 1084    collapse_matches: bool,
 1085    autoindent_mode: Option<AutoindentMode>,
 1086    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1087    input_enabled: bool,
 1088    use_modal_editing: bool,
 1089    read_only: bool,
 1090    leader_id: Option<CollaboratorId>,
 1091    remote_id: Option<ViewId>,
 1092    pub hover_state: HoverState,
 1093    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1094    gutter_hovered: bool,
 1095    hovered_link_state: Option<HoveredLinkState>,
 1096    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1097    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1098    active_inline_completion: Option<InlineCompletionState>,
 1099    /// Used to prevent flickering as the user types while the menu is open
 1100    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1101    edit_prediction_settings: EditPredictionSettings,
 1102    inline_completions_hidden_for_vim_mode: bool,
 1103    show_inline_completions_override: Option<bool>,
 1104    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1105    edit_prediction_preview: EditPredictionPreview,
 1106    edit_prediction_indent_conflict: bool,
 1107    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1108    inlay_hint_cache: InlayHintCache,
 1109    next_inlay_id: usize,
 1110    _subscriptions: Vec<Subscription>,
 1111    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1112    gutter_dimensions: GutterDimensions,
 1113    style: Option<EditorStyle>,
 1114    text_style_refinement: Option<TextStyleRefinement>,
 1115    next_editor_action_id: EditorActionId,
 1116    editor_actions: Rc<
 1117        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1118    >,
 1119    use_autoclose: bool,
 1120    use_auto_surround: bool,
 1121    auto_replace_emoji_shortcode: bool,
 1122    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1123    show_git_blame_gutter: bool,
 1124    show_git_blame_inline: bool,
 1125    show_git_blame_inline_delay_task: Option<Task<()>>,
 1126    git_blame_inline_enabled: bool,
 1127    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1128    serialize_dirty_buffers: bool,
 1129    show_selection_menu: Option<bool>,
 1130    blame: Option<Entity<GitBlame>>,
 1131    blame_subscription: Option<Subscription>,
 1132    custom_context_menu: Option<
 1133        Box<
 1134            dyn 'static
 1135                + Fn(
 1136                    &mut Self,
 1137                    DisplayPoint,
 1138                    &mut Window,
 1139                    &mut Context<Self>,
 1140                ) -> Option<Entity<ui::ContextMenu>>,
 1141        >,
 1142    >,
 1143    last_bounds: Option<Bounds<Pixels>>,
 1144    last_position_map: Option<Rc<PositionMap>>,
 1145    expect_bounds_change: Option<Bounds<Pixels>>,
 1146    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1147    tasks_update_task: Option<Task<()>>,
 1148    breakpoint_store: Option<Entity<BreakpointStore>>,
 1149    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1150    hovered_diff_hunk_row: Option<DisplayRow>,
 1151    pull_diagnostics_task: Task<()>,
 1152    in_project_search: bool,
 1153    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1154    breadcrumb_header: Option<String>,
 1155    focused_block: Option<FocusedBlock>,
 1156    next_scroll_position: NextScrollCursorCenterTopBottom,
 1157    addons: HashMap<TypeId, Box<dyn Addon>>,
 1158    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1159    load_diff_task: Option<Shared<Task<()>>>,
 1160    /// Whether we are temporarily displaying a diff other than git's
 1161    temporary_diff_override: bool,
 1162    selection_mark_mode: bool,
 1163    toggle_fold_multiple_buffers: Task<()>,
 1164    _scroll_cursor_center_top_bottom_task: Task<()>,
 1165    serialize_selections: Task<()>,
 1166    serialize_folds: Task<()>,
 1167    mouse_cursor_hidden: bool,
 1168    minimap: Option<Entity<Self>>,
 1169    hide_mouse_mode: HideMouseMode,
 1170    pub change_list: ChangeList,
 1171    inline_value_cache: InlineValueCache,
 1172    selection_drag_state: SelectionDragState,
 1173    next_color_inlay_id: usize,
 1174    colors: Option<LspColorData>,
 1175    folding_newlines: Task<()>,
 1176}
 1177
 1178#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1179enum NextScrollCursorCenterTopBottom {
 1180    #[default]
 1181    Center,
 1182    Top,
 1183    Bottom,
 1184}
 1185
 1186impl NextScrollCursorCenterTopBottom {
 1187    fn next(&self) -> Self {
 1188        match self {
 1189            Self::Center => Self::Top,
 1190            Self::Top => Self::Bottom,
 1191            Self::Bottom => Self::Center,
 1192        }
 1193    }
 1194}
 1195
 1196#[derive(Clone)]
 1197pub struct EditorSnapshot {
 1198    pub mode: EditorMode,
 1199    show_gutter: bool,
 1200    show_line_numbers: Option<bool>,
 1201    show_git_diff_gutter: Option<bool>,
 1202    show_code_actions: Option<bool>,
 1203    show_runnables: Option<bool>,
 1204    show_breakpoints: Option<bool>,
 1205    git_blame_gutter_max_author_length: Option<usize>,
 1206    pub display_snapshot: DisplaySnapshot,
 1207    pub placeholder_text: Option<Arc<str>>,
 1208    is_focused: bool,
 1209    scroll_anchor: ScrollAnchor,
 1210    ongoing_scroll: OngoingScroll,
 1211    current_line_highlight: CurrentLineHighlight,
 1212    gutter_hovered: bool,
 1213}
 1214
 1215#[derive(Default, Debug, Clone, Copy)]
 1216pub struct GutterDimensions {
 1217    pub left_padding: Pixels,
 1218    pub right_padding: Pixels,
 1219    pub width: Pixels,
 1220    pub margin: Pixels,
 1221    pub git_blame_entries_width: Option<Pixels>,
 1222}
 1223
 1224impl GutterDimensions {
 1225    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1226        Self {
 1227            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1228            ..Default::default()
 1229        }
 1230    }
 1231
 1232    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1233        -cx.text_system().descent(font_id, font_size)
 1234    }
 1235    /// The full width of the space taken up by the gutter.
 1236    pub fn full_width(&self) -> Pixels {
 1237        self.margin + self.width
 1238    }
 1239
 1240    /// The width of the space reserved for the fold indicators,
 1241    /// use alongside 'justify_end' and `gutter_width` to
 1242    /// right align content with the line numbers
 1243    pub fn fold_area_width(&self) -> Pixels {
 1244        self.margin + self.right_padding
 1245    }
 1246}
 1247
 1248struct CharacterDimensions {
 1249    em_width: Pixels,
 1250    em_advance: Pixels,
 1251    line_height: Pixels,
 1252}
 1253
 1254#[derive(Debug)]
 1255pub struct RemoteSelection {
 1256    pub replica_id: ReplicaId,
 1257    pub selection: Selection<Anchor>,
 1258    pub cursor_shape: CursorShape,
 1259    pub collaborator_id: CollaboratorId,
 1260    pub line_mode: bool,
 1261    pub user_name: Option<SharedString>,
 1262    pub color: PlayerColor,
 1263}
 1264
 1265#[derive(Clone, Debug)]
 1266struct SelectionHistoryEntry {
 1267    selections: Arc<[Selection<Anchor>]>,
 1268    select_next_state: Option<SelectNextState>,
 1269    select_prev_state: Option<SelectNextState>,
 1270    add_selections_state: Option<AddSelectionsState>,
 1271}
 1272
 1273#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1274enum SelectionHistoryMode {
 1275    Normal,
 1276    Undoing,
 1277    Redoing,
 1278    Skipping,
 1279}
 1280
 1281#[derive(Clone, PartialEq, Eq, Hash)]
 1282struct HoveredCursor {
 1283    replica_id: u16,
 1284    selection_id: usize,
 1285}
 1286
 1287impl Default for SelectionHistoryMode {
 1288    fn default() -> Self {
 1289        Self::Normal
 1290    }
 1291}
 1292
 1293#[derive(Debug)]
 1294/// SelectionEffects controls the side-effects of updating the selection.
 1295///
 1296/// The default behaviour does "what you mostly want":
 1297/// - it pushes to the nav history if the cursor moved by >10 lines
 1298/// - it re-triggers completion requests
 1299/// - it scrolls to fit
 1300///
 1301/// You might want to modify these behaviours. For example when doing a "jump"
 1302/// like go to definition, we always want to add to nav history; but when scrolling
 1303/// in vim mode we never do.
 1304///
 1305/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1306/// move.
 1307pub struct SelectionEffects {
 1308    nav_history: Option<bool>,
 1309    completions: bool,
 1310    scroll: Option<Autoscroll>,
 1311}
 1312
 1313impl Default for SelectionEffects {
 1314    fn default() -> Self {
 1315        Self {
 1316            nav_history: None,
 1317            completions: true,
 1318            scroll: Some(Autoscroll::fit()),
 1319        }
 1320    }
 1321}
 1322impl SelectionEffects {
 1323    pub fn scroll(scroll: Autoscroll) -> Self {
 1324        Self {
 1325            scroll: Some(scroll),
 1326            ..Default::default()
 1327        }
 1328    }
 1329
 1330    pub fn no_scroll() -> Self {
 1331        Self {
 1332            scroll: None,
 1333            ..Default::default()
 1334        }
 1335    }
 1336
 1337    pub fn completions(self, completions: bool) -> Self {
 1338        Self {
 1339            completions,
 1340            ..self
 1341        }
 1342    }
 1343
 1344    pub fn nav_history(self, nav_history: bool) -> Self {
 1345        Self {
 1346            nav_history: Some(nav_history),
 1347            ..self
 1348        }
 1349    }
 1350}
 1351
 1352struct DeferredSelectionEffectsState {
 1353    changed: bool,
 1354    effects: SelectionEffects,
 1355    old_cursor_position: Anchor,
 1356    history_entry: SelectionHistoryEntry,
 1357}
 1358
 1359#[derive(Default)]
 1360struct SelectionHistory {
 1361    #[allow(clippy::type_complexity)]
 1362    selections_by_transaction:
 1363        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1364    mode: SelectionHistoryMode,
 1365    undo_stack: VecDeque<SelectionHistoryEntry>,
 1366    redo_stack: VecDeque<SelectionHistoryEntry>,
 1367}
 1368
 1369impl SelectionHistory {
 1370    #[track_caller]
 1371    fn insert_transaction(
 1372        &mut self,
 1373        transaction_id: TransactionId,
 1374        selections: Arc<[Selection<Anchor>]>,
 1375    ) {
 1376        if selections.is_empty() {
 1377            log::error!(
 1378                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1379                std::panic::Location::caller()
 1380            );
 1381            return;
 1382        }
 1383        self.selections_by_transaction
 1384            .insert(transaction_id, (selections, None));
 1385    }
 1386
 1387    #[allow(clippy::type_complexity)]
 1388    fn transaction(
 1389        &self,
 1390        transaction_id: TransactionId,
 1391    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1392        self.selections_by_transaction.get(&transaction_id)
 1393    }
 1394
 1395    #[allow(clippy::type_complexity)]
 1396    fn transaction_mut(
 1397        &mut self,
 1398        transaction_id: TransactionId,
 1399    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1400        self.selections_by_transaction.get_mut(&transaction_id)
 1401    }
 1402
 1403    fn push(&mut self, entry: SelectionHistoryEntry) {
 1404        if !entry.selections.is_empty() {
 1405            match self.mode {
 1406                SelectionHistoryMode::Normal => {
 1407                    self.push_undo(entry);
 1408                    self.redo_stack.clear();
 1409                }
 1410                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1411                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1412                SelectionHistoryMode::Skipping => {}
 1413            }
 1414        }
 1415    }
 1416
 1417    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1418        if self
 1419            .undo_stack
 1420            .back()
 1421            .map_or(true, |e| e.selections != entry.selections)
 1422        {
 1423            self.undo_stack.push_back(entry);
 1424            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1425                self.undo_stack.pop_front();
 1426            }
 1427        }
 1428    }
 1429
 1430    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1431        if self
 1432            .redo_stack
 1433            .back()
 1434            .map_or(true, |e| e.selections != entry.selections)
 1435        {
 1436            self.redo_stack.push_back(entry);
 1437            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1438                self.redo_stack.pop_front();
 1439            }
 1440        }
 1441    }
 1442}
 1443
 1444#[derive(Clone, Copy)]
 1445pub struct RowHighlightOptions {
 1446    pub autoscroll: bool,
 1447    pub include_gutter: bool,
 1448}
 1449
 1450impl Default for RowHighlightOptions {
 1451    fn default() -> Self {
 1452        Self {
 1453            autoscroll: Default::default(),
 1454            include_gutter: true,
 1455        }
 1456    }
 1457}
 1458
 1459struct RowHighlight {
 1460    index: usize,
 1461    range: Range<Anchor>,
 1462    color: Hsla,
 1463    options: RowHighlightOptions,
 1464    type_id: TypeId,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsState {
 1469    groups: Vec<AddSelectionsGroup>,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsGroup {
 1474    above: bool,
 1475    stack: Vec<usize>,
 1476}
 1477
 1478#[derive(Clone)]
 1479struct SelectNextState {
 1480    query: AhoCorasick,
 1481    wordwise: bool,
 1482    done: bool,
 1483}
 1484
 1485impl std::fmt::Debug for SelectNextState {
 1486    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1487        f.debug_struct(std::any::type_name::<Self>())
 1488            .field("wordwise", &self.wordwise)
 1489            .field("done", &self.done)
 1490            .finish()
 1491    }
 1492}
 1493
 1494#[derive(Debug)]
 1495struct AutocloseRegion {
 1496    selection_id: usize,
 1497    range: Range<Anchor>,
 1498    pair: BracketPair,
 1499}
 1500
 1501#[derive(Debug)]
 1502struct SnippetState {
 1503    ranges: Vec<Vec<Range<Anchor>>>,
 1504    active_index: usize,
 1505    choices: Vec<Option<Vec<String>>>,
 1506}
 1507
 1508#[doc(hidden)]
 1509pub struct RenameState {
 1510    pub range: Range<Anchor>,
 1511    pub old_name: Arc<str>,
 1512    pub editor: Entity<Editor>,
 1513    block_id: CustomBlockId,
 1514}
 1515
 1516struct InvalidationStack<T>(Vec<T>);
 1517
 1518struct RegisteredInlineCompletionProvider {
 1519    provider: Arc<dyn InlineCompletionProviderHandle>,
 1520    _subscription: Subscription,
 1521}
 1522
 1523#[derive(Debug, PartialEq, Eq)]
 1524pub struct ActiveDiagnosticGroup {
 1525    pub active_range: Range<Anchor>,
 1526    pub active_message: String,
 1527    pub group_id: usize,
 1528    pub blocks: HashSet<CustomBlockId>,
 1529}
 1530
 1531#[derive(Debug, PartialEq, Eq)]
 1532
 1533pub(crate) enum ActiveDiagnostic {
 1534    None,
 1535    All,
 1536    Group(ActiveDiagnosticGroup),
 1537}
 1538
 1539#[derive(Serialize, Deserialize, Clone, Debug)]
 1540pub struct ClipboardSelection {
 1541    /// The number of bytes in this selection.
 1542    pub len: usize,
 1543    /// Whether this was a full-line selection.
 1544    pub is_entire_line: bool,
 1545    /// The indentation of the first line when this content was originally copied.
 1546    pub first_line_indent: u32,
 1547}
 1548
 1549// selections, scroll behavior, was newest selection reversed
 1550type SelectSyntaxNodeHistoryState = (
 1551    Box<[Selection<usize>]>,
 1552    SelectSyntaxNodeScrollBehavior,
 1553    bool,
 1554);
 1555
 1556#[derive(Default)]
 1557struct SelectSyntaxNodeHistory {
 1558    stack: Vec<SelectSyntaxNodeHistoryState>,
 1559    // disable temporarily to allow changing selections without losing the stack
 1560    pub disable_clearing: bool,
 1561}
 1562
 1563impl SelectSyntaxNodeHistory {
 1564    pub fn try_clear(&mut self) {
 1565        if !self.disable_clearing {
 1566            self.stack.clear();
 1567        }
 1568    }
 1569
 1570    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1571        self.stack.push(selection);
 1572    }
 1573
 1574    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1575        self.stack.pop()
 1576    }
 1577}
 1578
 1579enum SelectSyntaxNodeScrollBehavior {
 1580    CursorTop,
 1581    FitSelection,
 1582    CursorBottom,
 1583}
 1584
 1585#[derive(Debug)]
 1586pub(crate) struct NavigationData {
 1587    cursor_anchor: Anchor,
 1588    cursor_position: Point,
 1589    scroll_anchor: ScrollAnchor,
 1590    scroll_top_row: u32,
 1591}
 1592
 1593#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1594pub enum GotoDefinitionKind {
 1595    Symbol,
 1596    Declaration,
 1597    Type,
 1598    Implementation,
 1599}
 1600
 1601#[derive(Debug, Clone)]
 1602enum InlayHintRefreshReason {
 1603    ModifiersChanged(bool),
 1604    Toggle(bool),
 1605    SettingsChange(InlayHintSettings),
 1606    NewLinesShown,
 1607    BufferEdited(HashSet<Arc<Language>>),
 1608    RefreshRequested,
 1609    ExcerptsRemoved(Vec<ExcerptId>),
 1610}
 1611
 1612impl InlayHintRefreshReason {
 1613    fn description(&self) -> &'static str {
 1614        match self {
 1615            Self::ModifiersChanged(_) => "modifiers changed",
 1616            Self::Toggle(_) => "toggle",
 1617            Self::SettingsChange(_) => "settings change",
 1618            Self::NewLinesShown => "new lines shown",
 1619            Self::BufferEdited(_) => "buffer edited",
 1620            Self::RefreshRequested => "refresh requested",
 1621            Self::ExcerptsRemoved(_) => "excerpts removed",
 1622        }
 1623    }
 1624}
 1625
 1626pub enum FormatTarget {
 1627    Buffers(HashSet<Entity<Buffer>>),
 1628    Ranges(Vec<Range<MultiBufferPoint>>),
 1629}
 1630
 1631pub(crate) struct FocusedBlock {
 1632    id: BlockId,
 1633    focus_handle: WeakFocusHandle,
 1634}
 1635
 1636#[derive(Clone)]
 1637enum JumpData {
 1638    MultiBufferRow {
 1639        row: MultiBufferRow,
 1640        line_offset_from_top: u32,
 1641    },
 1642    MultiBufferPoint {
 1643        excerpt_id: ExcerptId,
 1644        position: Point,
 1645        anchor: text::Anchor,
 1646        line_offset_from_top: u32,
 1647    },
 1648}
 1649
 1650pub enum MultibufferSelectionMode {
 1651    First,
 1652    All,
 1653}
 1654
 1655#[derive(Clone, Copy, Debug, Default)]
 1656pub struct RewrapOptions {
 1657    pub override_language_settings: bool,
 1658    pub preserve_existing_whitespace: bool,
 1659}
 1660
 1661impl Editor {
 1662    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1663        let buffer = cx.new(|cx| Buffer::local("", cx));
 1664        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1665        Self::new(
 1666            EditorMode::SingleLine { auto_width: false },
 1667            buffer,
 1668            None,
 1669            window,
 1670            cx,
 1671        )
 1672    }
 1673
 1674    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(EditorMode::full(), buffer, None, window, cx)
 1678    }
 1679
 1680    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1681        let buffer = cx.new(|cx| Buffer::local("", cx));
 1682        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1683        Self::new(
 1684            EditorMode::SingleLine { auto_width: true },
 1685            buffer,
 1686            None,
 1687            window,
 1688            cx,
 1689        )
 1690    }
 1691
 1692    pub fn auto_height(
 1693        min_lines: usize,
 1694        max_lines: usize,
 1695        window: &mut Window,
 1696        cx: &mut Context<Self>,
 1697    ) -> Self {
 1698        let buffer = cx.new(|cx| Buffer::local("", cx));
 1699        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1700        Self::new(
 1701            EditorMode::AutoHeight {
 1702                min_lines,
 1703                max_lines: Some(max_lines),
 1704            },
 1705            buffer,
 1706            None,
 1707            window,
 1708            cx,
 1709        )
 1710    }
 1711
 1712    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1713    /// The editor grows as tall as needed to fit its content.
 1714    pub fn auto_height_unbounded(
 1715        min_lines: usize,
 1716        window: &mut Window,
 1717        cx: &mut Context<Self>,
 1718    ) -> Self {
 1719        let buffer = cx.new(|cx| Buffer::local("", cx));
 1720        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1721        Self::new(
 1722            EditorMode::AutoHeight {
 1723                min_lines,
 1724                max_lines: None,
 1725            },
 1726            buffer,
 1727            None,
 1728            window,
 1729            cx,
 1730        )
 1731    }
 1732
 1733    pub fn for_buffer(
 1734        buffer: Entity<Buffer>,
 1735        project: Option<Entity<Project>>,
 1736        window: &mut Window,
 1737        cx: &mut Context<Self>,
 1738    ) -> Self {
 1739        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1740        Self::new(EditorMode::full(), buffer, project, window, cx)
 1741    }
 1742
 1743    pub fn for_multibuffer(
 1744        buffer: Entity<MultiBuffer>,
 1745        project: Option<Entity<Project>>,
 1746        window: &mut Window,
 1747        cx: &mut Context<Self>,
 1748    ) -> Self {
 1749        Self::new(EditorMode::full(), buffer, project, window, cx)
 1750    }
 1751
 1752    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1753        let mut clone = Self::new(
 1754            self.mode.clone(),
 1755            self.buffer.clone(),
 1756            self.project.clone(),
 1757            window,
 1758            cx,
 1759        );
 1760        self.display_map.update(cx, |display_map, cx| {
 1761            let snapshot = display_map.snapshot(cx);
 1762            clone.display_map.update(cx, |display_map, cx| {
 1763                display_map.set_state(&snapshot, cx);
 1764            });
 1765        });
 1766        clone.folds_did_change(cx);
 1767        clone.selections.clone_state(&self.selections);
 1768        clone.scroll_manager.clone_state(&self.scroll_manager);
 1769        clone.searchable = self.searchable;
 1770        clone.read_only = self.read_only;
 1771        clone
 1772    }
 1773
 1774    pub fn new(
 1775        mode: EditorMode,
 1776        buffer: Entity<MultiBuffer>,
 1777        project: Option<Entity<Project>>,
 1778        window: &mut Window,
 1779        cx: &mut Context<Self>,
 1780    ) -> Self {
 1781        Editor::new_internal(mode, buffer, project, None, window, cx)
 1782    }
 1783
 1784    fn new_internal(
 1785        mode: EditorMode,
 1786        buffer: Entity<MultiBuffer>,
 1787        project: Option<Entity<Project>>,
 1788        display_map: Option<Entity<DisplayMap>>,
 1789        window: &mut Window,
 1790        cx: &mut Context<Self>,
 1791    ) -> Self {
 1792        debug_assert!(
 1793            display_map.is_none() || mode.is_minimap(),
 1794            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1795        );
 1796
 1797        let full_mode = mode.is_full();
 1798        let diagnostics_max_severity = if full_mode {
 1799            EditorSettings::get_global(cx)
 1800                .diagnostics_max_severity
 1801                .unwrap_or(DiagnosticSeverity::Hint)
 1802        } else {
 1803            DiagnosticSeverity::Off
 1804        };
 1805        let style = window.text_style();
 1806        let font_size = style.font_size.to_pixels(window.rem_size());
 1807        let editor = cx.entity().downgrade();
 1808        let fold_placeholder = FoldPlaceholder {
 1809            constrain_width: true,
 1810            render: Arc::new(move |fold_id, fold_range, cx| {
 1811                let editor = editor.clone();
 1812                div()
 1813                    .id(fold_id)
 1814                    .bg(cx.theme().colors().ghost_element_background)
 1815                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1816                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1817                    .rounded_xs()
 1818                    .size_full()
 1819                    .cursor_pointer()
 1820                    .child("")
 1821                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1822                    .on_click(move |_, _window, cx| {
 1823                        editor
 1824                            .update(cx, |editor, cx| {
 1825                                editor.unfold_ranges(
 1826                                    &[fold_range.start..fold_range.end],
 1827                                    true,
 1828                                    false,
 1829                                    cx,
 1830                                );
 1831                                cx.stop_propagation();
 1832                            })
 1833                            .ok();
 1834                    })
 1835                    .into_any()
 1836            }),
 1837            merge_adjacent: true,
 1838            ..FoldPlaceholder::default()
 1839        };
 1840        let display_map = display_map.unwrap_or_else(|| {
 1841            cx.new(|cx| {
 1842                DisplayMap::new(
 1843                    buffer.clone(),
 1844                    style.font(),
 1845                    font_size,
 1846                    None,
 1847                    FILE_HEADER_HEIGHT,
 1848                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1849                    fold_placeholder,
 1850                    diagnostics_max_severity,
 1851                    cx,
 1852                )
 1853            })
 1854        });
 1855
 1856        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1857
 1858        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1859
 1860        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1861            .then(|| language_settings::SoftWrap::None);
 1862
 1863        let mut project_subscriptions = Vec::new();
 1864        if mode.is_full() {
 1865            if let Some(project) = project.as_ref() {
 1866                project_subscriptions.push(cx.subscribe_in(
 1867                    project,
 1868                    window,
 1869                    |editor, _, event, window, cx| match event {
 1870                        project::Event::RefreshCodeLens => {
 1871                            // we always query lens with actions, without storing them, always refreshing them
 1872                        }
 1873                        project::Event::RefreshInlayHints => {
 1874                            editor
 1875                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1876                        }
 1877                        project::Event::LanguageServerAdded(..)
 1878                        | project::Event::LanguageServerRemoved(..) => {
 1879                            if editor.tasks_update_task.is_none() {
 1880                                editor.tasks_update_task =
 1881                                    Some(editor.refresh_runnables(window, cx));
 1882                            }
 1883                            editor.update_lsp_data(true, None, window, cx);
 1884                        }
 1885                        project::Event::SnippetEdit(id, snippet_edits) => {
 1886                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1887                                let focus_handle = editor.focus_handle(cx);
 1888                                if focus_handle.is_focused(window) {
 1889                                    let snapshot = buffer.read(cx).snapshot();
 1890                                    for (range, snippet) in snippet_edits {
 1891                                        let editor_range =
 1892                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1893                                        editor
 1894                                            .insert_snippet(
 1895                                                &[editor_range],
 1896                                                snippet.clone(),
 1897                                                window,
 1898                                                cx,
 1899                                            )
 1900                                            .ok();
 1901                                    }
 1902                                }
 1903                            }
 1904                        }
 1905                        _ => {}
 1906                    },
 1907                ));
 1908                if let Some(task_inventory) = project
 1909                    .read(cx)
 1910                    .task_store()
 1911                    .read(cx)
 1912                    .task_inventory()
 1913                    .cloned()
 1914                {
 1915                    project_subscriptions.push(cx.observe_in(
 1916                        &task_inventory,
 1917                        window,
 1918                        |editor, _, window, cx| {
 1919                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1920                        },
 1921                    ));
 1922                };
 1923
 1924                project_subscriptions.push(cx.subscribe_in(
 1925                    &project.read(cx).breakpoint_store(),
 1926                    window,
 1927                    |editor, _, event, window, cx| match event {
 1928                        BreakpointStoreEvent::ClearDebugLines => {
 1929                            editor.clear_row_highlights::<ActiveDebugLine>();
 1930                            editor.refresh_inline_values(cx);
 1931                        }
 1932                        BreakpointStoreEvent::SetDebugLine => {
 1933                            if editor.go_to_active_debug_line(window, cx) {
 1934                                cx.stop_propagation();
 1935                            }
 1936
 1937                            editor.refresh_inline_values(cx);
 1938                        }
 1939                        _ => {}
 1940                    },
 1941                ));
 1942                let git_store = project.read(cx).git_store().clone();
 1943                let project = project.clone();
 1944                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1945                    match event {
 1946                        GitStoreEvent::RepositoryUpdated(
 1947                            _,
 1948                            RepositoryEvent::Updated {
 1949                                new_instance: true, ..
 1950                            },
 1951                            _,
 1952                        ) => {
 1953                            this.load_diff_task = Some(
 1954                                update_uncommitted_diff_for_buffer(
 1955                                    cx.entity(),
 1956                                    &project,
 1957                                    this.buffer.read(cx).all_buffers(),
 1958                                    this.buffer.clone(),
 1959                                    cx,
 1960                                )
 1961                                .shared(),
 1962                            );
 1963                        }
 1964                        _ => {}
 1965                    }
 1966                }));
 1967            }
 1968        }
 1969
 1970        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1971
 1972        let inlay_hint_settings =
 1973            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1974        let focus_handle = cx.focus_handle();
 1975        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1976            .detach();
 1977        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1978            .detach();
 1979        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1980            .detach();
 1981        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1982            .detach();
 1983        cx.observe_pending_input(window, Self::observe_pending_input)
 1984            .detach();
 1985
 1986        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1987            Some(false)
 1988        } else {
 1989            None
 1990        };
 1991
 1992        let breakpoint_store = match (&mode, project.as_ref()) {
 1993            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1994            _ => None,
 1995        };
 1996
 1997        let mut code_action_providers = Vec::new();
 1998        let mut load_uncommitted_diff = None;
 1999        if let Some(project) = project.clone() {
 2000            load_uncommitted_diff = Some(
 2001                update_uncommitted_diff_for_buffer(
 2002                    cx.entity(),
 2003                    &project,
 2004                    buffer.read(cx).all_buffers(),
 2005                    buffer.clone(),
 2006                    cx,
 2007                )
 2008                .shared(),
 2009            );
 2010            code_action_providers.push(Rc::new(project) as Rc<_>);
 2011        }
 2012
 2013        let mut editor = Self {
 2014            focus_handle,
 2015            show_cursor_when_unfocused: false,
 2016            last_focused_descendant: None,
 2017            buffer: buffer.clone(),
 2018            display_map: display_map.clone(),
 2019            selections,
 2020            scroll_manager: ScrollManager::new(cx),
 2021            columnar_selection_state: None,
 2022            add_selections_state: None,
 2023            select_next_state: None,
 2024            select_prev_state: None,
 2025            selection_history: SelectionHistory::default(),
 2026            defer_selection_effects: false,
 2027            deferred_selection_effects_state: None,
 2028            autoclose_regions: Vec::new(),
 2029            snippet_stack: InvalidationStack::default(),
 2030            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2031            ime_transaction: None,
 2032            active_diagnostics: ActiveDiagnostic::None,
 2033            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2034            inline_diagnostics_update: Task::ready(()),
 2035            inline_diagnostics: Vec::new(),
 2036            soft_wrap_mode_override,
 2037            diagnostics_max_severity,
 2038            hard_wrap: None,
 2039            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2040            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2041            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2042            project,
 2043            blink_manager: blink_manager.clone(),
 2044            show_local_selections: true,
 2045            show_scrollbars: ScrollbarAxes {
 2046                horizontal: full_mode,
 2047                vertical: full_mode,
 2048            },
 2049            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2050            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2051            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2052            show_gutter: mode.is_full(),
 2053            show_line_numbers: None,
 2054            use_relative_line_numbers: None,
 2055            disable_expand_excerpt_buttons: false,
 2056            show_git_diff_gutter: None,
 2057            show_code_actions: None,
 2058            show_runnables: None,
 2059            show_breakpoints: None,
 2060            show_wrap_guides: None,
 2061            show_indent_guides,
 2062            placeholder_text: None,
 2063            highlight_order: 0,
 2064            highlighted_rows: HashMap::default(),
 2065            background_highlights: TreeMap::default(),
 2066            gutter_highlights: TreeMap::default(),
 2067            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2068            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2069            nav_history: None,
 2070            context_menu: RefCell::new(None),
 2071            context_menu_options: None,
 2072            mouse_context_menu: None,
 2073            completion_tasks: Vec::new(),
 2074            inline_blame_popover: None,
 2075            inline_blame_popover_show_task: None,
 2076            signature_help_state: SignatureHelpState::default(),
 2077            auto_signature_help: None,
 2078            find_all_references_task_sources: Vec::new(),
 2079            next_completion_id: 0,
 2080            next_inlay_id: 0,
 2081            code_action_providers,
 2082            available_code_actions: None,
 2083            code_actions_task: None,
 2084            quick_selection_highlight_task: None,
 2085            debounced_selection_highlight_task: None,
 2086            document_highlights_task: None,
 2087            linked_editing_range_task: None,
 2088            pending_rename: None,
 2089            searchable: true,
 2090            cursor_shape: EditorSettings::get_global(cx)
 2091                .cursor_shape
 2092                .unwrap_or_default(),
 2093            current_line_highlight: None,
 2094            autoindent_mode: Some(AutoindentMode::EachLine),
 2095            collapse_matches: false,
 2096            workspace: None,
 2097            input_enabled: true,
 2098            use_modal_editing: mode.is_full(),
 2099            read_only: mode.is_minimap(),
 2100            use_autoclose: true,
 2101            use_auto_surround: true,
 2102            auto_replace_emoji_shortcode: false,
 2103            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2104            leader_id: None,
 2105            remote_id: None,
 2106            hover_state: HoverState::default(),
 2107            pending_mouse_down: None,
 2108            hovered_link_state: None,
 2109            edit_prediction_provider: None,
 2110            active_inline_completion: None,
 2111            stale_inline_completion_in_menu: None,
 2112            edit_prediction_preview: EditPredictionPreview::Inactive {
 2113                released_too_fast: false,
 2114            },
 2115            inline_diagnostics_enabled: mode.is_full(),
 2116            diagnostics_enabled: mode.is_full(),
 2117            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2118            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2119
 2120            gutter_hovered: false,
 2121            pixel_position_of_newest_cursor: None,
 2122            last_bounds: None,
 2123            last_position_map: None,
 2124            expect_bounds_change: None,
 2125            gutter_dimensions: GutterDimensions::default(),
 2126            style: None,
 2127            show_cursor_names: false,
 2128            hovered_cursors: HashMap::default(),
 2129            next_editor_action_id: EditorActionId::default(),
 2130            editor_actions: Rc::default(),
 2131            inline_completions_hidden_for_vim_mode: false,
 2132            show_inline_completions_override: None,
 2133            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2134            edit_prediction_settings: EditPredictionSettings::Disabled,
 2135            edit_prediction_indent_conflict: false,
 2136            edit_prediction_requires_modifier_in_indent_conflict: true,
 2137            custom_context_menu: None,
 2138            show_git_blame_gutter: false,
 2139            show_git_blame_inline: false,
 2140            show_selection_menu: None,
 2141            show_git_blame_inline_delay_task: None,
 2142            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2143            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2144            serialize_dirty_buffers: !mode.is_minimap()
 2145                && ProjectSettings::get_global(cx)
 2146                    .session
 2147                    .restore_unsaved_buffers,
 2148            blame: None,
 2149            blame_subscription: None,
 2150            tasks: BTreeMap::default(),
 2151
 2152            breakpoint_store,
 2153            gutter_breakpoint_indicator: (None, None),
 2154            hovered_diff_hunk_row: None,
 2155            _subscriptions: vec![
 2156                cx.observe(&buffer, Self::on_buffer_changed),
 2157                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2158                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2159                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2160                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2161                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2162                cx.observe_window_activation(window, |editor, window, cx| {
 2163                    let active = window.is_window_active();
 2164                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2165                        if active {
 2166                            blink_manager.enable(cx);
 2167                        } else {
 2168                            blink_manager.disable(cx);
 2169                        }
 2170                    });
 2171                    if active {
 2172                        editor.show_mouse_cursor(cx);
 2173                    }
 2174                }),
 2175            ],
 2176            tasks_update_task: None,
 2177            pull_diagnostics_task: Task::ready(()),
 2178            colors: None,
 2179            next_color_inlay_id: 0,
 2180            linked_edit_ranges: Default::default(),
 2181            in_project_search: false,
 2182            previous_search_ranges: None,
 2183            breadcrumb_header: None,
 2184            focused_block: None,
 2185            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2186            addons: HashMap::default(),
 2187            registered_buffers: HashMap::default(),
 2188            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2189            selection_mark_mode: false,
 2190            toggle_fold_multiple_buffers: Task::ready(()),
 2191            serialize_selections: Task::ready(()),
 2192            serialize_folds: Task::ready(()),
 2193            text_style_refinement: None,
 2194            load_diff_task: load_uncommitted_diff,
 2195            temporary_diff_override: false,
 2196            mouse_cursor_hidden: false,
 2197            minimap: None,
 2198            hide_mouse_mode: EditorSettings::get_global(cx)
 2199                .hide_mouse
 2200                .unwrap_or_default(),
 2201            change_list: ChangeList::new(),
 2202            mode,
 2203            selection_drag_state: SelectionDragState::None,
 2204            folding_newlines: Task::ready(()),
 2205        };
 2206        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2207            editor
 2208                ._subscriptions
 2209                .push(cx.observe(breakpoints, |_, _, cx| {
 2210                    cx.notify();
 2211                }));
 2212        }
 2213        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2214        editor._subscriptions.extend(project_subscriptions);
 2215
 2216        editor._subscriptions.push(cx.subscribe_in(
 2217            &cx.entity(),
 2218            window,
 2219            |editor, _, e: &EditorEvent, window, cx| match e {
 2220                EditorEvent::ScrollPositionChanged { local, .. } => {
 2221                    if *local {
 2222                        let new_anchor = editor.scroll_manager.anchor();
 2223                        let snapshot = editor.snapshot(window, cx);
 2224                        editor.update_restoration_data(cx, move |data| {
 2225                            data.scroll_position = (
 2226                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2227                                new_anchor.offset,
 2228                            );
 2229                        });
 2230                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2231                        editor.inline_blame_popover.take();
 2232                    }
 2233                }
 2234                EditorEvent::Edited { .. } => {
 2235                    if !vim_enabled(cx) {
 2236                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2237                        let pop_state = editor
 2238                            .change_list
 2239                            .last()
 2240                            .map(|previous| {
 2241                                previous.len() == selections.len()
 2242                                    && previous.iter().enumerate().all(|(ix, p)| {
 2243                                        p.to_display_point(&map).row()
 2244                                            == selections[ix].head().row()
 2245                                    })
 2246                            })
 2247                            .unwrap_or(false);
 2248                        let new_positions = selections
 2249                            .into_iter()
 2250                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2251                            .collect();
 2252                        editor
 2253                            .change_list
 2254                            .push_to_change_list(pop_state, new_positions);
 2255                    }
 2256                }
 2257                _ => (),
 2258            },
 2259        ));
 2260
 2261        if let Some(dap_store) = editor
 2262            .project
 2263            .as_ref()
 2264            .map(|project| project.read(cx).dap_store())
 2265        {
 2266            let weak_editor = cx.weak_entity();
 2267
 2268            editor
 2269                ._subscriptions
 2270                .push(
 2271                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2272                        let session_entity = cx.entity();
 2273                        weak_editor
 2274                            .update(cx, |editor, cx| {
 2275                                editor._subscriptions.push(
 2276                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2277                                );
 2278                            })
 2279                            .ok();
 2280                    }),
 2281                );
 2282
 2283            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2284                editor
 2285                    ._subscriptions
 2286                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2287            }
 2288        }
 2289
 2290        // skip adding the initial selection to selection history
 2291        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2292        editor.end_selection(window, cx);
 2293        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2294
 2295        editor.scroll_manager.show_scrollbars(window, cx);
 2296        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2297
 2298        if full_mode {
 2299            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2300            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2301
 2302            if editor.git_blame_inline_enabled {
 2303                editor.start_git_blame_inline(false, window, cx);
 2304            }
 2305
 2306            editor.go_to_active_debug_line(window, cx);
 2307
 2308            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2309                if let Some(project) = editor.project.as_ref() {
 2310                    let handle = project.update(cx, |project, cx| {
 2311                        project.register_buffer_with_language_servers(&buffer, cx)
 2312                    });
 2313                    editor
 2314                        .registered_buffers
 2315                        .insert(buffer.read(cx).remote_id(), handle);
 2316                }
 2317            }
 2318
 2319            editor.minimap =
 2320                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2321            editor.colors = Some(LspColorData::new(cx));
 2322            editor.update_lsp_data(false, None, window, cx);
 2323        }
 2324
 2325        editor.report_editor_event("Editor Opened", None, cx);
 2326        editor
 2327    }
 2328
 2329    pub fn deploy_mouse_context_menu(
 2330        &mut self,
 2331        position: gpui::Point<Pixels>,
 2332        context_menu: Entity<ContextMenu>,
 2333        window: &mut Window,
 2334        cx: &mut Context<Self>,
 2335    ) {
 2336        self.mouse_context_menu = Some(MouseContextMenu::new(
 2337            self,
 2338            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2339            context_menu,
 2340            window,
 2341            cx,
 2342        ));
 2343    }
 2344
 2345    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2346        self.mouse_context_menu
 2347            .as_ref()
 2348            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2349    }
 2350
 2351    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2352        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2353    }
 2354
 2355    fn key_context_internal(
 2356        &self,
 2357        has_active_edit_prediction: bool,
 2358        window: &Window,
 2359        cx: &App,
 2360    ) -> KeyContext {
 2361        let mut key_context = KeyContext::new_with_defaults();
 2362        key_context.add("Editor");
 2363        let mode = match self.mode {
 2364            EditorMode::SingleLine { .. } => "single_line",
 2365            EditorMode::AutoHeight { .. } => "auto_height",
 2366            EditorMode::Minimap { .. } => "minimap",
 2367            EditorMode::Full { .. } => "full",
 2368        };
 2369
 2370        if EditorSettings::jupyter_enabled(cx) {
 2371            key_context.add("jupyter");
 2372        }
 2373
 2374        key_context.set("mode", mode);
 2375        if self.pending_rename.is_some() {
 2376            key_context.add("renaming");
 2377        }
 2378
 2379        match self.context_menu.borrow().as_ref() {
 2380            Some(CodeContextMenu::Completions(_)) => {
 2381                key_context.add("menu");
 2382                key_context.add("showing_completions");
 2383            }
 2384            Some(CodeContextMenu::CodeActions(_)) => {
 2385                key_context.add("menu");
 2386                key_context.add("showing_code_actions")
 2387            }
 2388            None => {}
 2389        }
 2390
 2391        if self.signature_help_state.has_multiple_signatures() {
 2392            key_context.add("showing_signature_help");
 2393        }
 2394
 2395        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2396        if !self.focus_handle(cx).contains_focused(window, cx)
 2397            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2398        {
 2399            for addon in self.addons.values() {
 2400                addon.extend_key_context(&mut key_context, cx)
 2401            }
 2402        }
 2403
 2404        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2405            if let Some(extension) = singleton_buffer
 2406                .read(cx)
 2407                .file()
 2408                .and_then(|file| file.path().extension()?.to_str())
 2409            {
 2410                key_context.set("extension", extension.to_string());
 2411            }
 2412        } else {
 2413            key_context.add("multibuffer");
 2414        }
 2415
 2416        if has_active_edit_prediction {
 2417            if self.edit_prediction_in_conflict() {
 2418                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2419            } else {
 2420                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2421                key_context.add("copilot_suggestion");
 2422            }
 2423        }
 2424
 2425        if self.selection_mark_mode {
 2426            key_context.add("selection_mode");
 2427        }
 2428
 2429        key_context
 2430    }
 2431
 2432    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2433        if self.mouse_cursor_hidden {
 2434            self.mouse_cursor_hidden = false;
 2435            cx.notify();
 2436        }
 2437    }
 2438
 2439    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2440        let hide_mouse_cursor = match origin {
 2441            HideMouseCursorOrigin::TypingAction => {
 2442                matches!(
 2443                    self.hide_mouse_mode,
 2444                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2445                )
 2446            }
 2447            HideMouseCursorOrigin::MovementAction => {
 2448                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2449            }
 2450        };
 2451        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2452            self.mouse_cursor_hidden = hide_mouse_cursor;
 2453            cx.notify();
 2454        }
 2455    }
 2456
 2457    pub fn edit_prediction_in_conflict(&self) -> bool {
 2458        if !self.show_edit_predictions_in_menu() {
 2459            return false;
 2460        }
 2461
 2462        let showing_completions = self
 2463            .context_menu
 2464            .borrow()
 2465            .as_ref()
 2466            .map_or(false, |context| {
 2467                matches!(context, CodeContextMenu::Completions(_))
 2468            });
 2469
 2470        showing_completions
 2471            || self.edit_prediction_requires_modifier()
 2472            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2473            // bindings to insert tab characters.
 2474            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2475    }
 2476
 2477    pub fn accept_edit_prediction_keybind(
 2478        &self,
 2479        accept_partial: bool,
 2480        window: &Window,
 2481        cx: &App,
 2482    ) -> AcceptEditPredictionBinding {
 2483        let key_context = self.key_context_internal(true, window, cx);
 2484        let in_conflict = self.edit_prediction_in_conflict();
 2485
 2486        let bindings = if accept_partial {
 2487            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2488        } else {
 2489            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2490        };
 2491
 2492        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2493        // just the first one.
 2494        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2495            !in_conflict
 2496                || binding
 2497                    .keystrokes()
 2498                    .first()
 2499                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2500        }))
 2501    }
 2502
 2503    pub fn new_file(
 2504        workspace: &mut Workspace,
 2505        _: &workspace::NewFile,
 2506        window: &mut Window,
 2507        cx: &mut Context<Workspace>,
 2508    ) {
 2509        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2510            "Failed to create buffer",
 2511            window,
 2512            cx,
 2513            |e, _, _| match e.error_code() {
 2514                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2515                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2516                e.error_tag("required").unwrap_or("the latest version")
 2517            )),
 2518                _ => None,
 2519            },
 2520        );
 2521    }
 2522
 2523    pub fn new_in_workspace(
 2524        workspace: &mut Workspace,
 2525        window: &mut Window,
 2526        cx: &mut Context<Workspace>,
 2527    ) -> Task<Result<Entity<Editor>>> {
 2528        let project = workspace.project().clone();
 2529        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2530
 2531        cx.spawn_in(window, async move |workspace, cx| {
 2532            let buffer = create.await?;
 2533            workspace.update_in(cx, |workspace, window, cx| {
 2534                let editor =
 2535                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2536                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2537                editor
 2538            })
 2539        })
 2540    }
 2541
 2542    fn new_file_vertical(
 2543        workspace: &mut Workspace,
 2544        _: &workspace::NewFileSplitVertical,
 2545        window: &mut Window,
 2546        cx: &mut Context<Workspace>,
 2547    ) {
 2548        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2549    }
 2550
 2551    fn new_file_horizontal(
 2552        workspace: &mut Workspace,
 2553        _: &workspace::NewFileSplitHorizontal,
 2554        window: &mut Window,
 2555        cx: &mut Context<Workspace>,
 2556    ) {
 2557        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2558    }
 2559
 2560    fn new_file_in_direction(
 2561        workspace: &mut Workspace,
 2562        direction: SplitDirection,
 2563        window: &mut Window,
 2564        cx: &mut Context<Workspace>,
 2565    ) {
 2566        let project = workspace.project().clone();
 2567        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2568
 2569        cx.spawn_in(window, async move |workspace, cx| {
 2570            let buffer = create.await?;
 2571            workspace.update_in(cx, move |workspace, window, cx| {
 2572                workspace.split_item(
 2573                    direction,
 2574                    Box::new(
 2575                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2576                    ),
 2577                    window,
 2578                    cx,
 2579                )
 2580            })?;
 2581            anyhow::Ok(())
 2582        })
 2583        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2584            match e.error_code() {
 2585                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2586                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2587                e.error_tag("required").unwrap_or("the latest version")
 2588            )),
 2589                _ => None,
 2590            }
 2591        });
 2592    }
 2593
 2594    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2595        self.leader_id
 2596    }
 2597
 2598    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2599        &self.buffer
 2600    }
 2601
 2602    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2603        self.workspace.as_ref()?.0.upgrade()
 2604    }
 2605
 2606    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2607        self.buffer().read(cx).title(cx)
 2608    }
 2609
 2610    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2611        let git_blame_gutter_max_author_length = self
 2612            .render_git_blame_gutter(cx)
 2613            .then(|| {
 2614                if let Some(blame) = self.blame.as_ref() {
 2615                    let max_author_length =
 2616                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2617                    Some(max_author_length)
 2618                } else {
 2619                    None
 2620                }
 2621            })
 2622            .flatten();
 2623
 2624        EditorSnapshot {
 2625            mode: self.mode.clone(),
 2626            show_gutter: self.show_gutter,
 2627            show_line_numbers: self.show_line_numbers,
 2628            show_git_diff_gutter: self.show_git_diff_gutter,
 2629            show_code_actions: self.show_code_actions,
 2630            show_runnables: self.show_runnables,
 2631            show_breakpoints: self.show_breakpoints,
 2632            git_blame_gutter_max_author_length,
 2633            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2634            scroll_anchor: self.scroll_manager.anchor(),
 2635            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2636            placeholder_text: self.placeholder_text.clone(),
 2637            is_focused: self.focus_handle.is_focused(window),
 2638            current_line_highlight: self
 2639                .current_line_highlight
 2640                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2641            gutter_hovered: self.gutter_hovered,
 2642        }
 2643    }
 2644
 2645    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2646        self.buffer.read(cx).language_at(point, cx)
 2647    }
 2648
 2649    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2650        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2651    }
 2652
 2653    pub fn active_excerpt(
 2654        &self,
 2655        cx: &App,
 2656    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2657        self.buffer
 2658            .read(cx)
 2659            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2660    }
 2661
 2662    pub fn mode(&self) -> &EditorMode {
 2663        &self.mode
 2664    }
 2665
 2666    pub fn set_mode(&mut self, mode: EditorMode) {
 2667        self.mode = mode;
 2668    }
 2669
 2670    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2671        self.collaboration_hub.as_deref()
 2672    }
 2673
 2674    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2675        self.collaboration_hub = Some(hub);
 2676    }
 2677
 2678    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2679        self.in_project_search = in_project_search;
 2680    }
 2681
 2682    pub fn set_custom_context_menu(
 2683        &mut self,
 2684        f: impl 'static
 2685        + Fn(
 2686            &mut Self,
 2687            DisplayPoint,
 2688            &mut Window,
 2689            &mut Context<Self>,
 2690        ) -> Option<Entity<ui::ContextMenu>>,
 2691    ) {
 2692        self.custom_context_menu = Some(Box::new(f))
 2693    }
 2694
 2695    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2696        self.completion_provider = provider;
 2697    }
 2698
 2699    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2700        self.semantics_provider.clone()
 2701    }
 2702
 2703    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2704        self.semantics_provider = provider;
 2705    }
 2706
 2707    pub fn set_edit_prediction_provider<T>(
 2708        &mut self,
 2709        provider: Option<Entity<T>>,
 2710        window: &mut Window,
 2711        cx: &mut Context<Self>,
 2712    ) where
 2713        T: EditPredictionProvider,
 2714    {
 2715        self.edit_prediction_provider =
 2716            provider.map(|provider| RegisteredInlineCompletionProvider {
 2717                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2718                    if this.focus_handle.is_focused(window) {
 2719                        this.update_visible_inline_completion(window, cx);
 2720                    }
 2721                }),
 2722                provider: Arc::new(provider),
 2723            });
 2724        self.update_edit_prediction_settings(cx);
 2725        self.refresh_inline_completion(false, false, window, cx);
 2726    }
 2727
 2728    pub fn placeholder_text(&self) -> Option<&str> {
 2729        self.placeholder_text.as_deref()
 2730    }
 2731
 2732    pub fn set_placeholder_text(
 2733        &mut self,
 2734        placeholder_text: impl Into<Arc<str>>,
 2735        cx: &mut Context<Self>,
 2736    ) {
 2737        let placeholder_text = Some(placeholder_text.into());
 2738        if self.placeholder_text != placeholder_text {
 2739            self.placeholder_text = placeholder_text;
 2740            cx.notify();
 2741        }
 2742    }
 2743
 2744    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2745        self.cursor_shape = cursor_shape;
 2746
 2747        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2748        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2749
 2750        cx.notify();
 2751    }
 2752
 2753    pub fn set_current_line_highlight(
 2754        &mut self,
 2755        current_line_highlight: Option<CurrentLineHighlight>,
 2756    ) {
 2757        self.current_line_highlight = current_line_highlight;
 2758    }
 2759
 2760    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2761        self.collapse_matches = collapse_matches;
 2762    }
 2763
 2764    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2765        let buffers = self.buffer.read(cx).all_buffers();
 2766        let Some(project) = self.project.as_ref() else {
 2767            return;
 2768        };
 2769        project.update(cx, |project, cx| {
 2770            for buffer in buffers {
 2771                self.registered_buffers
 2772                    .entry(buffer.read(cx).remote_id())
 2773                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2774            }
 2775        })
 2776    }
 2777
 2778    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2779        if self.collapse_matches {
 2780            return range.start..range.start;
 2781        }
 2782        range.clone()
 2783    }
 2784
 2785    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2786        if self.display_map.read(cx).clip_at_line_ends != clip {
 2787            self.display_map
 2788                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2789        }
 2790    }
 2791
 2792    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2793        self.input_enabled = input_enabled;
 2794    }
 2795
 2796    pub fn set_inline_completions_hidden_for_vim_mode(
 2797        &mut self,
 2798        hidden: bool,
 2799        window: &mut Window,
 2800        cx: &mut Context<Self>,
 2801    ) {
 2802        if hidden != self.inline_completions_hidden_for_vim_mode {
 2803            self.inline_completions_hidden_for_vim_mode = hidden;
 2804            if hidden {
 2805                self.update_visible_inline_completion(window, cx);
 2806            } else {
 2807                self.refresh_inline_completion(true, false, window, cx);
 2808            }
 2809        }
 2810    }
 2811
 2812    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2813        self.menu_inline_completions_policy = value;
 2814    }
 2815
 2816    pub fn set_autoindent(&mut self, autoindent: bool) {
 2817        if autoindent {
 2818            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2819        } else {
 2820            self.autoindent_mode = None;
 2821        }
 2822    }
 2823
 2824    pub fn read_only(&self, cx: &App) -> bool {
 2825        self.read_only || self.buffer.read(cx).read_only()
 2826    }
 2827
 2828    pub fn set_read_only(&mut self, read_only: bool) {
 2829        self.read_only = read_only;
 2830    }
 2831
 2832    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2833        self.use_autoclose = autoclose;
 2834    }
 2835
 2836    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2837        self.use_auto_surround = auto_surround;
 2838    }
 2839
 2840    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2841        self.auto_replace_emoji_shortcode = auto_replace;
 2842    }
 2843
 2844    pub fn toggle_edit_predictions(
 2845        &mut self,
 2846        _: &ToggleEditPrediction,
 2847        window: &mut Window,
 2848        cx: &mut Context<Self>,
 2849    ) {
 2850        if self.show_inline_completions_override.is_some() {
 2851            self.set_show_edit_predictions(None, window, cx);
 2852        } else {
 2853            let show_edit_predictions = !self.edit_predictions_enabled();
 2854            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2855        }
 2856    }
 2857
 2858    pub fn set_show_edit_predictions(
 2859        &mut self,
 2860        show_edit_predictions: Option<bool>,
 2861        window: &mut Window,
 2862        cx: &mut Context<Self>,
 2863    ) {
 2864        self.show_inline_completions_override = show_edit_predictions;
 2865        self.update_edit_prediction_settings(cx);
 2866
 2867        if let Some(false) = show_edit_predictions {
 2868            self.discard_inline_completion(false, cx);
 2869        } else {
 2870            self.refresh_inline_completion(false, true, window, cx);
 2871        }
 2872    }
 2873
 2874    fn inline_completions_disabled_in_scope(
 2875        &self,
 2876        buffer: &Entity<Buffer>,
 2877        buffer_position: language::Anchor,
 2878        cx: &App,
 2879    ) -> bool {
 2880        let snapshot = buffer.read(cx).snapshot();
 2881        let settings = snapshot.settings_at(buffer_position, cx);
 2882
 2883        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2884            return false;
 2885        };
 2886
 2887        scope.override_name().map_or(false, |scope_name| {
 2888            settings
 2889                .edit_predictions_disabled_in
 2890                .iter()
 2891                .any(|s| s == scope_name)
 2892        })
 2893    }
 2894
 2895    pub fn set_use_modal_editing(&mut self, to: bool) {
 2896        self.use_modal_editing = to;
 2897    }
 2898
 2899    pub fn use_modal_editing(&self) -> bool {
 2900        self.use_modal_editing
 2901    }
 2902
 2903    fn selections_did_change(
 2904        &mut self,
 2905        local: bool,
 2906        old_cursor_position: &Anchor,
 2907        effects: SelectionEffects,
 2908        window: &mut Window,
 2909        cx: &mut Context<Self>,
 2910    ) {
 2911        window.invalidate_character_coordinates();
 2912
 2913        // Copy selections to primary selection buffer
 2914        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2915        if local {
 2916            let selections = self.selections.all::<usize>(cx);
 2917            let buffer_handle = self.buffer.read(cx).read(cx);
 2918
 2919            let mut text = String::new();
 2920            for (index, selection) in selections.iter().enumerate() {
 2921                let text_for_selection = buffer_handle
 2922                    .text_for_range(selection.start..selection.end)
 2923                    .collect::<String>();
 2924
 2925                text.push_str(&text_for_selection);
 2926                if index != selections.len() - 1 {
 2927                    text.push('\n');
 2928                }
 2929            }
 2930
 2931            if !text.is_empty() {
 2932                cx.write_to_primary(ClipboardItem::new_string(text));
 2933            }
 2934        }
 2935
 2936        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2937            self.buffer.update(cx, |buffer, cx| {
 2938                buffer.set_active_selections(
 2939                    &self.selections.disjoint_anchors(),
 2940                    self.selections.line_mode,
 2941                    self.cursor_shape,
 2942                    cx,
 2943                )
 2944            });
 2945        }
 2946        let display_map = self
 2947            .display_map
 2948            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2949        let buffer = &display_map.buffer_snapshot;
 2950        if self.selections.count() == 1 {
 2951            self.add_selections_state = None;
 2952        }
 2953        self.select_next_state = None;
 2954        self.select_prev_state = None;
 2955        self.select_syntax_node_history.try_clear();
 2956        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2957        self.snippet_stack
 2958            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2959        self.take_rename(false, window, cx);
 2960
 2961        let newest_selection = self.selections.newest_anchor();
 2962        let new_cursor_position = newest_selection.head();
 2963        let selection_start = newest_selection.start;
 2964
 2965        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2966            self.push_to_nav_history(
 2967                *old_cursor_position,
 2968                Some(new_cursor_position.to_point(buffer)),
 2969                false,
 2970                effects.nav_history == Some(true),
 2971                cx,
 2972            );
 2973        }
 2974
 2975        if local {
 2976            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2977                if !self.registered_buffers.contains_key(&buffer_id) {
 2978                    if let Some(project) = self.project.as_ref() {
 2979                        project.update(cx, |project, cx| {
 2980                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2981                                return;
 2982                            };
 2983                            self.registered_buffers.insert(
 2984                                buffer_id,
 2985                                project.register_buffer_with_language_servers(&buffer, cx),
 2986                            );
 2987                        })
 2988                    }
 2989                }
 2990            }
 2991
 2992            let mut context_menu = self.context_menu.borrow_mut();
 2993            let completion_menu = match context_menu.as_ref() {
 2994                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2995                Some(CodeContextMenu::CodeActions(_)) => {
 2996                    *context_menu = None;
 2997                    None
 2998                }
 2999                None => None,
 3000            };
 3001            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3002            drop(context_menu);
 3003
 3004            if effects.completions {
 3005                if let Some(completion_position) = completion_position {
 3006                    let start_offset = selection_start.to_offset(buffer);
 3007                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3008                    let continue_showing = if position_matches {
 3009                        if self.snippet_stack.is_empty() {
 3010                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3011                        } else {
 3012                            // Snippet choices can be shown even when the cursor is in whitespace.
 3013                            // Dismissing the menu with actions like backspace is handled by
 3014                            // invalidation regions.
 3015                            true
 3016                        }
 3017                    } else {
 3018                        false
 3019                    };
 3020
 3021                    if continue_showing {
 3022                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3023                    } else {
 3024                        self.hide_context_menu(window, cx);
 3025                    }
 3026                }
 3027            }
 3028
 3029            hide_hover(self, cx);
 3030
 3031            if old_cursor_position.to_display_point(&display_map).row()
 3032                != new_cursor_position.to_display_point(&display_map).row()
 3033            {
 3034                self.available_code_actions.take();
 3035            }
 3036            self.refresh_code_actions(window, cx);
 3037            self.refresh_document_highlights(cx);
 3038            self.refresh_selected_text_highlights(false, window, cx);
 3039            refresh_matching_bracket_highlights(self, window, cx);
 3040            self.update_visible_inline_completion(window, cx);
 3041            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3042            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3043            self.inline_blame_popover.take();
 3044            if self.git_blame_inline_enabled {
 3045                self.start_inline_blame_timer(window, cx);
 3046            }
 3047        }
 3048
 3049        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3050        cx.emit(EditorEvent::SelectionsChanged { local });
 3051
 3052        let selections = &self.selections.disjoint;
 3053        if selections.len() == 1 {
 3054            cx.emit(SearchEvent::ActiveMatchChanged)
 3055        }
 3056        if local {
 3057            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3058                let inmemory_selections = selections
 3059                    .iter()
 3060                    .map(|s| {
 3061                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3062                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3063                    })
 3064                    .collect();
 3065                self.update_restoration_data(cx, |data| {
 3066                    data.selections = inmemory_selections;
 3067                });
 3068
 3069                if WorkspaceSettings::get(None, cx).restore_on_startup
 3070                    != RestoreOnStartupBehavior::None
 3071                {
 3072                    if let Some(workspace_id) =
 3073                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3074                    {
 3075                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3076                        let selections = selections.clone();
 3077                        let background_executor = cx.background_executor().clone();
 3078                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3079                        self.serialize_selections = cx.background_spawn(async move {
 3080                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3081                            let db_selections = selections
 3082                                .iter()
 3083                                .map(|selection| {
 3084                                    (
 3085                                        selection.start.to_offset(&snapshot),
 3086                                        selection.end.to_offset(&snapshot),
 3087                                    )
 3088                                })
 3089                                .collect();
 3090
 3091                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3092                                .await
 3093                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3094                                .log_err();
 3095                        });
 3096                    }
 3097                }
 3098            }
 3099        }
 3100
 3101        cx.notify();
 3102    }
 3103
 3104    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3105        use text::ToOffset as _;
 3106        use text::ToPoint as _;
 3107
 3108        if self.mode.is_minimap()
 3109            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3110        {
 3111            return;
 3112        }
 3113
 3114        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3115            return;
 3116        };
 3117
 3118        let snapshot = singleton.read(cx).snapshot();
 3119        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3120            let display_snapshot = display_map.snapshot(cx);
 3121
 3122            display_snapshot
 3123                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3124                .map(|fold| {
 3125                    fold.range.start.text_anchor.to_point(&snapshot)
 3126                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3127                })
 3128                .collect()
 3129        });
 3130        self.update_restoration_data(cx, |data| {
 3131            data.folds = inmemory_folds;
 3132        });
 3133
 3134        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3135            return;
 3136        };
 3137        let background_executor = cx.background_executor().clone();
 3138        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3139        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3140            display_map
 3141                .snapshot(cx)
 3142                .folds_in_range(0..snapshot.len())
 3143                .map(|fold| {
 3144                    (
 3145                        fold.range.start.text_anchor.to_offset(&snapshot),
 3146                        fold.range.end.text_anchor.to_offset(&snapshot),
 3147                    )
 3148                })
 3149                .collect()
 3150        });
 3151        self.serialize_folds = cx.background_spawn(async move {
 3152            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3153            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3154                .await
 3155                .with_context(|| {
 3156                    format!(
 3157                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3158                    )
 3159                })
 3160                .log_err();
 3161        });
 3162    }
 3163
 3164    pub fn sync_selections(
 3165        &mut self,
 3166        other: Entity<Editor>,
 3167        cx: &mut Context<Self>,
 3168    ) -> gpui::Subscription {
 3169        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3170        self.selections.change_with(cx, |selections| {
 3171            selections.select_anchors(other_selections);
 3172        });
 3173
 3174        let other_subscription =
 3175            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3176                EditorEvent::SelectionsChanged { local: true } => {
 3177                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3178                    if other_selections.is_empty() {
 3179                        return;
 3180                    }
 3181                    this.selections.change_with(cx, |selections| {
 3182                        selections.select_anchors(other_selections);
 3183                    });
 3184                }
 3185                _ => {}
 3186            });
 3187
 3188        let this_subscription =
 3189            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3190                EditorEvent::SelectionsChanged { local: true } => {
 3191                    let these_selections = this.selections.disjoint.to_vec();
 3192                    if these_selections.is_empty() {
 3193                        return;
 3194                    }
 3195                    other.update(cx, |other_editor, cx| {
 3196                        other_editor.selections.change_with(cx, |selections| {
 3197                            selections.select_anchors(these_selections);
 3198                        })
 3199                    });
 3200                }
 3201                _ => {}
 3202            });
 3203
 3204        Subscription::join(other_subscription, this_subscription)
 3205    }
 3206
 3207    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3208    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3209    /// effects of selection change occur at the end of the transaction.
 3210    pub fn change_selections<R>(
 3211        &mut self,
 3212        effects: SelectionEffects,
 3213        window: &mut Window,
 3214        cx: &mut Context<Self>,
 3215        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3216    ) -> R {
 3217        if let Some(state) = &mut self.deferred_selection_effects_state {
 3218            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3219            state.effects.completions = effects.completions;
 3220            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3221            let (changed, result) = self.selections.change_with(cx, change);
 3222            state.changed |= changed;
 3223            return result;
 3224        }
 3225        let mut state = DeferredSelectionEffectsState {
 3226            changed: false,
 3227            effects,
 3228            old_cursor_position: self.selections.newest_anchor().head(),
 3229            history_entry: SelectionHistoryEntry {
 3230                selections: self.selections.disjoint_anchors(),
 3231                select_next_state: self.select_next_state.clone(),
 3232                select_prev_state: self.select_prev_state.clone(),
 3233                add_selections_state: self.add_selections_state.clone(),
 3234            },
 3235        };
 3236        let (changed, result) = self.selections.change_with(cx, change);
 3237        state.changed = state.changed || changed;
 3238        if self.defer_selection_effects {
 3239            self.deferred_selection_effects_state = Some(state);
 3240        } else {
 3241            self.apply_selection_effects(state, window, cx);
 3242        }
 3243        result
 3244    }
 3245
 3246    /// Defers the effects of selection change, so that the effects of multiple calls to
 3247    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3248    /// to selection history and the state of popovers based on selection position aren't
 3249    /// erroneously updated.
 3250    pub fn with_selection_effects_deferred<R>(
 3251        &mut self,
 3252        window: &mut Window,
 3253        cx: &mut Context<Self>,
 3254        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3255    ) -> R {
 3256        let already_deferred = self.defer_selection_effects;
 3257        self.defer_selection_effects = true;
 3258        let result = update(self, window, cx);
 3259        if !already_deferred {
 3260            self.defer_selection_effects = false;
 3261            if let Some(state) = self.deferred_selection_effects_state.take() {
 3262                self.apply_selection_effects(state, window, cx);
 3263            }
 3264        }
 3265        result
 3266    }
 3267
 3268    fn apply_selection_effects(
 3269        &mut self,
 3270        state: DeferredSelectionEffectsState,
 3271        window: &mut Window,
 3272        cx: &mut Context<Self>,
 3273    ) {
 3274        if state.changed {
 3275            self.selection_history.push(state.history_entry);
 3276
 3277            if let Some(autoscroll) = state.effects.scroll {
 3278                self.request_autoscroll(autoscroll, cx);
 3279            }
 3280
 3281            let old_cursor_position = &state.old_cursor_position;
 3282
 3283            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3284
 3285            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3286                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3287            }
 3288        }
 3289    }
 3290
 3291    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3292    where
 3293        I: IntoIterator<Item = (Range<S>, T)>,
 3294        S: ToOffset,
 3295        T: Into<Arc<str>>,
 3296    {
 3297        if self.read_only(cx) {
 3298            return;
 3299        }
 3300
 3301        self.buffer
 3302            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3303    }
 3304
 3305    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3306    where
 3307        I: IntoIterator<Item = (Range<S>, T)>,
 3308        S: ToOffset,
 3309        T: Into<Arc<str>>,
 3310    {
 3311        if self.read_only(cx) {
 3312            return;
 3313        }
 3314
 3315        self.buffer.update(cx, |buffer, cx| {
 3316            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3317        });
 3318    }
 3319
 3320    pub fn edit_with_block_indent<I, S, T>(
 3321        &mut self,
 3322        edits: I,
 3323        original_indent_columns: Vec<Option<u32>>,
 3324        cx: &mut Context<Self>,
 3325    ) where
 3326        I: IntoIterator<Item = (Range<S>, T)>,
 3327        S: ToOffset,
 3328        T: Into<Arc<str>>,
 3329    {
 3330        if self.read_only(cx) {
 3331            return;
 3332        }
 3333
 3334        self.buffer.update(cx, |buffer, cx| {
 3335            buffer.edit(
 3336                edits,
 3337                Some(AutoindentMode::Block {
 3338                    original_indent_columns,
 3339                }),
 3340                cx,
 3341            )
 3342        });
 3343    }
 3344
 3345    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3346        self.hide_context_menu(window, cx);
 3347
 3348        match phase {
 3349            SelectPhase::Begin {
 3350                position,
 3351                add,
 3352                click_count,
 3353            } => self.begin_selection(position, add, click_count, window, cx),
 3354            SelectPhase::BeginColumnar {
 3355                position,
 3356                goal_column,
 3357                reset,
 3358                mode,
 3359            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3360            SelectPhase::Extend {
 3361                position,
 3362                click_count,
 3363            } => self.extend_selection(position, click_count, window, cx),
 3364            SelectPhase::Update {
 3365                position,
 3366                goal_column,
 3367                scroll_delta,
 3368            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3369            SelectPhase::End => self.end_selection(window, cx),
 3370        }
 3371    }
 3372
 3373    fn extend_selection(
 3374        &mut self,
 3375        position: DisplayPoint,
 3376        click_count: usize,
 3377        window: &mut Window,
 3378        cx: &mut Context<Self>,
 3379    ) {
 3380        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3381        let tail = self.selections.newest::<usize>(cx).tail();
 3382        self.begin_selection(position, false, click_count, window, cx);
 3383
 3384        let position = position.to_offset(&display_map, Bias::Left);
 3385        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3386
 3387        let mut pending_selection = self
 3388            .selections
 3389            .pending_anchor()
 3390            .expect("extend_selection not called with pending selection");
 3391        if position >= tail {
 3392            pending_selection.start = tail_anchor;
 3393        } else {
 3394            pending_selection.end = tail_anchor;
 3395            pending_selection.reversed = true;
 3396        }
 3397
 3398        let mut pending_mode = self.selections.pending_mode().unwrap();
 3399        match &mut pending_mode {
 3400            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3401            _ => {}
 3402        }
 3403
 3404        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3405            SelectionEffects::scroll(Autoscroll::fit())
 3406        } else {
 3407            SelectionEffects::no_scroll()
 3408        };
 3409
 3410        self.change_selections(effects, window, cx, |s| {
 3411            s.set_pending(pending_selection, pending_mode)
 3412        });
 3413    }
 3414
 3415    fn begin_selection(
 3416        &mut self,
 3417        position: DisplayPoint,
 3418        add: bool,
 3419        click_count: usize,
 3420        window: &mut Window,
 3421        cx: &mut Context<Self>,
 3422    ) {
 3423        if !self.focus_handle.is_focused(window) {
 3424            self.last_focused_descendant = None;
 3425            window.focus(&self.focus_handle);
 3426        }
 3427
 3428        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3429        let buffer = &display_map.buffer_snapshot;
 3430        let position = display_map.clip_point(position, Bias::Left);
 3431
 3432        let start;
 3433        let end;
 3434        let mode;
 3435        let mut auto_scroll;
 3436        match click_count {
 3437            1 => {
 3438                start = buffer.anchor_before(position.to_point(&display_map));
 3439                end = start;
 3440                mode = SelectMode::Character;
 3441                auto_scroll = true;
 3442            }
 3443            2 => {
 3444                let position = display_map
 3445                    .clip_point(position, Bias::Left)
 3446                    .to_offset(&display_map, Bias::Left);
 3447                let (range, _) = buffer.surrounding_word(position, false);
 3448                start = buffer.anchor_before(range.start);
 3449                end = buffer.anchor_before(range.end);
 3450                mode = SelectMode::Word(start..end);
 3451                auto_scroll = true;
 3452            }
 3453            3 => {
 3454                let position = display_map
 3455                    .clip_point(position, Bias::Left)
 3456                    .to_point(&display_map);
 3457                let line_start = display_map.prev_line_boundary(position).0;
 3458                let next_line_start = buffer.clip_point(
 3459                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3460                    Bias::Left,
 3461                );
 3462                start = buffer.anchor_before(line_start);
 3463                end = buffer.anchor_before(next_line_start);
 3464                mode = SelectMode::Line(start..end);
 3465                auto_scroll = true;
 3466            }
 3467            _ => {
 3468                start = buffer.anchor_before(0);
 3469                end = buffer.anchor_before(buffer.len());
 3470                mode = SelectMode::All;
 3471                auto_scroll = false;
 3472            }
 3473        }
 3474        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3475
 3476        let point_to_delete: Option<usize> = {
 3477            let selected_points: Vec<Selection<Point>> =
 3478                self.selections.disjoint_in_range(start..end, cx);
 3479
 3480            if !add || click_count > 1 {
 3481                None
 3482            } else if !selected_points.is_empty() {
 3483                Some(selected_points[0].id)
 3484            } else {
 3485                let clicked_point_already_selected =
 3486                    self.selections.disjoint.iter().find(|selection| {
 3487                        selection.start.to_point(buffer) == start.to_point(buffer)
 3488                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3489                    });
 3490
 3491                clicked_point_already_selected.map(|selection| selection.id)
 3492            }
 3493        };
 3494
 3495        let selections_count = self.selections.count();
 3496        let effects = if auto_scroll {
 3497            SelectionEffects::default()
 3498        } else {
 3499            SelectionEffects::no_scroll()
 3500        };
 3501
 3502        self.change_selections(effects, window, cx, |s| {
 3503            if let Some(point_to_delete) = point_to_delete {
 3504                s.delete(point_to_delete);
 3505
 3506                if selections_count == 1 {
 3507                    s.set_pending_anchor_range(start..end, mode);
 3508                }
 3509            } else {
 3510                if !add {
 3511                    s.clear_disjoint();
 3512                }
 3513
 3514                s.set_pending_anchor_range(start..end, mode);
 3515            }
 3516        });
 3517    }
 3518
 3519    fn begin_columnar_selection(
 3520        &mut self,
 3521        position: DisplayPoint,
 3522        goal_column: u32,
 3523        reset: bool,
 3524        mode: ColumnarMode,
 3525        window: &mut Window,
 3526        cx: &mut Context<Self>,
 3527    ) {
 3528        if !self.focus_handle.is_focused(window) {
 3529            self.last_focused_descendant = None;
 3530            window.focus(&self.focus_handle);
 3531        }
 3532
 3533        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3534
 3535        if reset {
 3536            let pointer_position = display_map
 3537                .buffer_snapshot
 3538                .anchor_before(position.to_point(&display_map));
 3539
 3540            self.change_selections(
 3541                SelectionEffects::scroll(Autoscroll::newest()),
 3542                window,
 3543                cx,
 3544                |s| {
 3545                    s.clear_disjoint();
 3546                    s.set_pending_anchor_range(
 3547                        pointer_position..pointer_position,
 3548                        SelectMode::Character,
 3549                    );
 3550                },
 3551            );
 3552        };
 3553
 3554        let tail = self.selections.newest::<Point>(cx).tail();
 3555        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3556        self.columnar_selection_state = match mode {
 3557            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3558                selection_tail: selection_anchor,
 3559                display_point: if reset {
 3560                    if position.column() != goal_column {
 3561                        Some(DisplayPoint::new(position.row(), goal_column))
 3562                    } else {
 3563                        None
 3564                    }
 3565                } else {
 3566                    None
 3567                },
 3568            }),
 3569            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3570                selection_tail: selection_anchor,
 3571            }),
 3572        };
 3573
 3574        if !reset {
 3575            self.select_columns(position, goal_column, &display_map, window, cx);
 3576        }
 3577    }
 3578
 3579    fn update_selection(
 3580        &mut self,
 3581        position: DisplayPoint,
 3582        goal_column: u32,
 3583        scroll_delta: gpui::Point<f32>,
 3584        window: &mut Window,
 3585        cx: &mut Context<Self>,
 3586    ) {
 3587        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3588
 3589        if self.columnar_selection_state.is_some() {
 3590            self.select_columns(position, goal_column, &display_map, window, cx);
 3591        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3592            let buffer = &display_map.buffer_snapshot;
 3593            let head;
 3594            let tail;
 3595            let mode = self.selections.pending_mode().unwrap();
 3596            match &mode {
 3597                SelectMode::Character => {
 3598                    head = position.to_point(&display_map);
 3599                    tail = pending.tail().to_point(buffer);
 3600                }
 3601                SelectMode::Word(original_range) => {
 3602                    let offset = display_map
 3603                        .clip_point(position, Bias::Left)
 3604                        .to_offset(&display_map, Bias::Left);
 3605                    let original_range = original_range.to_offset(buffer);
 3606
 3607                    let head_offset = if buffer.is_inside_word(offset, false)
 3608                        || original_range.contains(&offset)
 3609                    {
 3610                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3611                        if word_range.start < original_range.start {
 3612                            word_range.start
 3613                        } else {
 3614                            word_range.end
 3615                        }
 3616                    } else {
 3617                        offset
 3618                    };
 3619
 3620                    head = head_offset.to_point(buffer);
 3621                    if head_offset <= original_range.start {
 3622                        tail = original_range.end.to_point(buffer);
 3623                    } else {
 3624                        tail = original_range.start.to_point(buffer);
 3625                    }
 3626                }
 3627                SelectMode::Line(original_range) => {
 3628                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3629
 3630                    let position = display_map
 3631                        .clip_point(position, Bias::Left)
 3632                        .to_point(&display_map);
 3633                    let line_start = display_map.prev_line_boundary(position).0;
 3634                    let next_line_start = buffer.clip_point(
 3635                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3636                        Bias::Left,
 3637                    );
 3638
 3639                    if line_start < original_range.start {
 3640                        head = line_start
 3641                    } else {
 3642                        head = next_line_start
 3643                    }
 3644
 3645                    if head <= original_range.start {
 3646                        tail = original_range.end;
 3647                    } else {
 3648                        tail = original_range.start;
 3649                    }
 3650                }
 3651                SelectMode::All => {
 3652                    return;
 3653                }
 3654            };
 3655
 3656            if head < tail {
 3657                pending.start = buffer.anchor_before(head);
 3658                pending.end = buffer.anchor_before(tail);
 3659                pending.reversed = true;
 3660            } else {
 3661                pending.start = buffer.anchor_before(tail);
 3662                pending.end = buffer.anchor_before(head);
 3663                pending.reversed = false;
 3664            }
 3665
 3666            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3667                s.set_pending(pending, mode);
 3668            });
 3669        } else {
 3670            log::error!("update_selection dispatched with no pending selection");
 3671            return;
 3672        }
 3673
 3674        self.apply_scroll_delta(scroll_delta, window, cx);
 3675        cx.notify();
 3676    }
 3677
 3678    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3679        self.columnar_selection_state.take();
 3680        if self.selections.pending_anchor().is_some() {
 3681            let selections = self.selections.all::<usize>(cx);
 3682            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3683                s.select(selections);
 3684                s.clear_pending();
 3685            });
 3686        }
 3687    }
 3688
 3689    fn select_columns(
 3690        &mut self,
 3691        head: DisplayPoint,
 3692        goal_column: u32,
 3693        display_map: &DisplaySnapshot,
 3694        window: &mut Window,
 3695        cx: &mut Context<Self>,
 3696    ) {
 3697        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3698            return;
 3699        };
 3700
 3701        let tail = match columnar_state {
 3702            ColumnarSelectionState::FromMouse {
 3703                selection_tail,
 3704                display_point,
 3705            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3706            ColumnarSelectionState::FromSelection { selection_tail } => {
 3707                selection_tail.to_display_point(&display_map)
 3708            }
 3709        };
 3710
 3711        let start_row = cmp::min(tail.row(), head.row());
 3712        let end_row = cmp::max(tail.row(), head.row());
 3713        let start_column = cmp::min(tail.column(), goal_column);
 3714        let end_column = cmp::max(tail.column(), goal_column);
 3715        let reversed = start_column < tail.column();
 3716
 3717        let selection_ranges = (start_row.0..=end_row.0)
 3718            .map(DisplayRow)
 3719            .filter_map(|row| {
 3720                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3721                    || start_column <= display_map.line_len(row))
 3722                    && !display_map.is_block_line(row)
 3723                {
 3724                    let start = display_map
 3725                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3726                        .to_point(display_map);
 3727                    let end = display_map
 3728                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3729                        .to_point(display_map);
 3730                    if reversed {
 3731                        Some(end..start)
 3732                    } else {
 3733                        Some(start..end)
 3734                    }
 3735                } else {
 3736                    None
 3737                }
 3738            })
 3739            .collect::<Vec<_>>();
 3740
 3741        let ranges = match columnar_state {
 3742            ColumnarSelectionState::FromMouse { .. } => {
 3743                let mut non_empty_ranges = selection_ranges
 3744                    .iter()
 3745                    .filter(|selection_range| selection_range.start != selection_range.end)
 3746                    .peekable();
 3747                if non_empty_ranges.peek().is_some() {
 3748                    non_empty_ranges.cloned().collect()
 3749                } else {
 3750                    selection_ranges
 3751                }
 3752            }
 3753            _ => selection_ranges,
 3754        };
 3755
 3756        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3757            s.select_ranges(ranges);
 3758        });
 3759        cx.notify();
 3760    }
 3761
 3762    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3763        self.selections
 3764            .all_adjusted(cx)
 3765            .iter()
 3766            .any(|selection| !selection.is_empty())
 3767    }
 3768
 3769    pub fn has_pending_nonempty_selection(&self) -> bool {
 3770        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3771            Some(Selection { start, end, .. }) => start != end,
 3772            None => false,
 3773        };
 3774
 3775        pending_nonempty_selection
 3776            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3777    }
 3778
 3779    pub fn has_pending_selection(&self) -> bool {
 3780        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3781    }
 3782
 3783    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3784        self.selection_mark_mode = false;
 3785        self.selection_drag_state = SelectionDragState::None;
 3786
 3787        if self.clear_expanded_diff_hunks(cx) {
 3788            cx.notify();
 3789            return;
 3790        }
 3791        if self.dismiss_menus_and_popups(true, window, cx) {
 3792            return;
 3793        }
 3794
 3795        if self.mode.is_full()
 3796            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3797        {
 3798            return;
 3799        }
 3800
 3801        cx.propagate();
 3802    }
 3803
 3804    pub fn dismiss_menus_and_popups(
 3805        &mut self,
 3806        is_user_requested: bool,
 3807        window: &mut Window,
 3808        cx: &mut Context<Self>,
 3809    ) -> bool {
 3810        if self.take_rename(false, window, cx).is_some() {
 3811            return true;
 3812        }
 3813
 3814        if hide_hover(self, cx) {
 3815            return true;
 3816        }
 3817
 3818        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3819            return true;
 3820        }
 3821
 3822        if self.hide_context_menu(window, cx).is_some() {
 3823            return true;
 3824        }
 3825
 3826        if self.mouse_context_menu.take().is_some() {
 3827            return true;
 3828        }
 3829
 3830        if is_user_requested && self.discard_inline_completion(true, cx) {
 3831            return true;
 3832        }
 3833
 3834        if self.snippet_stack.pop().is_some() {
 3835            return true;
 3836        }
 3837
 3838        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3839            self.dismiss_diagnostics(cx);
 3840            return true;
 3841        }
 3842
 3843        false
 3844    }
 3845
 3846    fn linked_editing_ranges_for(
 3847        &self,
 3848        selection: Range<text::Anchor>,
 3849        cx: &App,
 3850    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3851        if self.linked_edit_ranges.is_empty() {
 3852            return None;
 3853        }
 3854        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3855            selection.end.buffer_id.and_then(|end_buffer_id| {
 3856                if selection.start.buffer_id != Some(end_buffer_id) {
 3857                    return None;
 3858                }
 3859                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3860                let snapshot = buffer.read(cx).snapshot();
 3861                self.linked_edit_ranges
 3862                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3863                    .map(|ranges| (ranges, snapshot, buffer))
 3864            })?;
 3865        use text::ToOffset as TO;
 3866        // find offset from the start of current range to current cursor position
 3867        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3868
 3869        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3870        let start_difference = start_offset - start_byte_offset;
 3871        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3872        let end_difference = end_offset - start_byte_offset;
 3873        // Current range has associated linked ranges.
 3874        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3875        for range in linked_ranges.iter() {
 3876            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3877            let end_offset = start_offset + end_difference;
 3878            let start_offset = start_offset + start_difference;
 3879            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3880                continue;
 3881            }
 3882            if self.selections.disjoint_anchor_ranges().any(|s| {
 3883                if s.start.buffer_id != selection.start.buffer_id
 3884                    || s.end.buffer_id != selection.end.buffer_id
 3885                {
 3886                    return false;
 3887                }
 3888                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3889                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3890            }) {
 3891                continue;
 3892            }
 3893            let start = buffer_snapshot.anchor_after(start_offset);
 3894            let end = buffer_snapshot.anchor_after(end_offset);
 3895            linked_edits
 3896                .entry(buffer.clone())
 3897                .or_default()
 3898                .push(start..end);
 3899        }
 3900        Some(linked_edits)
 3901    }
 3902
 3903    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3904        let text: Arc<str> = text.into();
 3905
 3906        if self.read_only(cx) {
 3907            return;
 3908        }
 3909
 3910        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3911
 3912        let selections = self.selections.all_adjusted(cx);
 3913        let mut bracket_inserted = false;
 3914        let mut edits = Vec::new();
 3915        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3916        let mut new_selections = Vec::with_capacity(selections.len());
 3917        let mut new_autoclose_regions = Vec::new();
 3918        let snapshot = self.buffer.read(cx).read(cx);
 3919        let mut clear_linked_edit_ranges = false;
 3920
 3921        for (selection, autoclose_region) in
 3922            self.selections_with_autoclose_regions(selections, &snapshot)
 3923        {
 3924            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3925                // Determine if the inserted text matches the opening or closing
 3926                // bracket of any of this language's bracket pairs.
 3927                let mut bracket_pair = None;
 3928                let mut is_bracket_pair_start = false;
 3929                let mut is_bracket_pair_end = false;
 3930                if !text.is_empty() {
 3931                    let mut bracket_pair_matching_end = None;
 3932                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3933                    //  and they are removing the character that triggered IME popup.
 3934                    for (pair, enabled) in scope.brackets() {
 3935                        if !pair.close && !pair.surround {
 3936                            continue;
 3937                        }
 3938
 3939                        if enabled && pair.start.ends_with(text.as_ref()) {
 3940                            let prefix_len = pair.start.len() - text.len();
 3941                            let preceding_text_matches_prefix = prefix_len == 0
 3942                                || (selection.start.column >= (prefix_len as u32)
 3943                                    && snapshot.contains_str_at(
 3944                                        Point::new(
 3945                                            selection.start.row,
 3946                                            selection.start.column - (prefix_len as u32),
 3947                                        ),
 3948                                        &pair.start[..prefix_len],
 3949                                    ));
 3950                            if preceding_text_matches_prefix {
 3951                                bracket_pair = Some(pair.clone());
 3952                                is_bracket_pair_start = true;
 3953                                break;
 3954                            }
 3955                        }
 3956                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3957                        {
 3958                            // take first bracket pair matching end, but don't break in case a later bracket
 3959                            // pair matches start
 3960                            bracket_pair_matching_end = Some(pair.clone());
 3961                        }
 3962                    }
 3963                    if let Some(end) = bracket_pair_matching_end
 3964                        && bracket_pair.is_none()
 3965                    {
 3966                        bracket_pair = Some(end);
 3967                        is_bracket_pair_end = true;
 3968                    }
 3969                }
 3970
 3971                if let Some(bracket_pair) = bracket_pair {
 3972                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3973                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3974                    let auto_surround =
 3975                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3976                    if selection.is_empty() {
 3977                        if is_bracket_pair_start {
 3978                            // If the inserted text is a suffix of an opening bracket and the
 3979                            // selection is preceded by the rest of the opening bracket, then
 3980                            // insert the closing bracket.
 3981                            let following_text_allows_autoclose = snapshot
 3982                                .chars_at(selection.start)
 3983                                .next()
 3984                                .map_or(true, |c| scope.should_autoclose_before(c));
 3985
 3986                            let preceding_text_allows_autoclose = selection.start.column == 0
 3987                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3988                                    true,
 3989                                    |c| {
 3990                                        bracket_pair.start != bracket_pair.end
 3991                                            || !snapshot
 3992                                                .char_classifier_at(selection.start)
 3993                                                .is_word(c)
 3994                                    },
 3995                                );
 3996
 3997                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3998                                && bracket_pair.start.len() == 1
 3999                            {
 4000                                let target = bracket_pair.start.chars().next().unwrap();
 4001                                let current_line_count = snapshot
 4002                                    .reversed_chars_at(selection.start)
 4003                                    .take_while(|&c| c != '\n')
 4004                                    .filter(|&c| c == target)
 4005                                    .count();
 4006                                current_line_count % 2 == 1
 4007                            } else {
 4008                                false
 4009                            };
 4010
 4011                            if autoclose
 4012                                && bracket_pair.close
 4013                                && following_text_allows_autoclose
 4014                                && preceding_text_allows_autoclose
 4015                                && !is_closing_quote
 4016                            {
 4017                                let anchor = snapshot.anchor_before(selection.end);
 4018                                new_selections.push((selection.map(|_| anchor), text.len()));
 4019                                new_autoclose_regions.push((
 4020                                    anchor,
 4021                                    text.len(),
 4022                                    selection.id,
 4023                                    bracket_pair.clone(),
 4024                                ));
 4025                                edits.push((
 4026                                    selection.range(),
 4027                                    format!("{}{}", text, bracket_pair.end).into(),
 4028                                ));
 4029                                bracket_inserted = true;
 4030                                continue;
 4031                            }
 4032                        }
 4033
 4034                        if let Some(region) = autoclose_region {
 4035                            // If the selection is followed by an auto-inserted closing bracket,
 4036                            // then don't insert that closing bracket again; just move the selection
 4037                            // past the closing bracket.
 4038                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4039                                && text.as_ref() == region.pair.end.as_str();
 4040                            if should_skip {
 4041                                let anchor = snapshot.anchor_after(selection.end);
 4042                                new_selections
 4043                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4044                                continue;
 4045                            }
 4046                        }
 4047
 4048                        let always_treat_brackets_as_autoclosed = snapshot
 4049                            .language_settings_at(selection.start, cx)
 4050                            .always_treat_brackets_as_autoclosed;
 4051                        if always_treat_brackets_as_autoclosed
 4052                            && is_bracket_pair_end
 4053                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4054                        {
 4055                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4056                            // and the inserted text is a closing bracket and the selection is followed
 4057                            // by the closing bracket then move the selection past the closing bracket.
 4058                            let anchor = snapshot.anchor_after(selection.end);
 4059                            new_selections.push((selection.map(|_| anchor), text.len()));
 4060                            continue;
 4061                        }
 4062                    }
 4063                    // If an opening bracket is 1 character long and is typed while
 4064                    // text is selected, then surround that text with the bracket pair.
 4065                    else if auto_surround
 4066                        && bracket_pair.surround
 4067                        && is_bracket_pair_start
 4068                        && bracket_pair.start.chars().count() == 1
 4069                    {
 4070                        edits.push((selection.start..selection.start, text.clone()));
 4071                        edits.push((
 4072                            selection.end..selection.end,
 4073                            bracket_pair.end.as_str().into(),
 4074                        ));
 4075                        bracket_inserted = true;
 4076                        new_selections.push((
 4077                            Selection {
 4078                                id: selection.id,
 4079                                start: snapshot.anchor_after(selection.start),
 4080                                end: snapshot.anchor_before(selection.end),
 4081                                reversed: selection.reversed,
 4082                                goal: selection.goal,
 4083                            },
 4084                            0,
 4085                        ));
 4086                        continue;
 4087                    }
 4088                }
 4089            }
 4090
 4091            if self.auto_replace_emoji_shortcode
 4092                && selection.is_empty()
 4093                && text.as_ref().ends_with(':')
 4094            {
 4095                if let Some(possible_emoji_short_code) =
 4096                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4097                {
 4098                    if !possible_emoji_short_code.is_empty() {
 4099                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4100                            let emoji_shortcode_start = Point::new(
 4101                                selection.start.row,
 4102                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4103                            );
 4104
 4105                            // Remove shortcode from buffer
 4106                            edits.push((
 4107                                emoji_shortcode_start..selection.start,
 4108                                "".to_string().into(),
 4109                            ));
 4110                            new_selections.push((
 4111                                Selection {
 4112                                    id: selection.id,
 4113                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4114                                    end: snapshot.anchor_before(selection.start),
 4115                                    reversed: selection.reversed,
 4116                                    goal: selection.goal,
 4117                                },
 4118                                0,
 4119                            ));
 4120
 4121                            // Insert emoji
 4122                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4123                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4124                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4125
 4126                            continue;
 4127                        }
 4128                    }
 4129                }
 4130            }
 4131
 4132            // If not handling any auto-close operation, then just replace the selected
 4133            // text with the given input and move the selection to the end of the
 4134            // newly inserted text.
 4135            let anchor = snapshot.anchor_after(selection.end);
 4136            if !self.linked_edit_ranges.is_empty() {
 4137                let start_anchor = snapshot.anchor_before(selection.start);
 4138
 4139                let is_word_char = text.chars().next().map_or(true, |char| {
 4140                    let classifier = snapshot
 4141                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4142                        .ignore_punctuation(true);
 4143                    classifier.is_word(char)
 4144                });
 4145
 4146                if is_word_char {
 4147                    if let Some(ranges) = self
 4148                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4149                    {
 4150                        for (buffer, edits) in ranges {
 4151                            linked_edits
 4152                                .entry(buffer.clone())
 4153                                .or_default()
 4154                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4155                        }
 4156                    }
 4157                } else {
 4158                    clear_linked_edit_ranges = true;
 4159                }
 4160            }
 4161
 4162            new_selections.push((selection.map(|_| anchor), 0));
 4163            edits.push((selection.start..selection.end, text.clone()));
 4164        }
 4165
 4166        drop(snapshot);
 4167
 4168        self.transact(window, cx, |this, window, cx| {
 4169            if clear_linked_edit_ranges {
 4170                this.linked_edit_ranges.clear();
 4171            }
 4172            let initial_buffer_versions =
 4173                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4174
 4175            this.buffer.update(cx, |buffer, cx| {
 4176                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4177            });
 4178            for (buffer, edits) in linked_edits {
 4179                buffer.update(cx, |buffer, cx| {
 4180                    let snapshot = buffer.snapshot();
 4181                    let edits = edits
 4182                        .into_iter()
 4183                        .map(|(range, text)| {
 4184                            use text::ToPoint as TP;
 4185                            let end_point = TP::to_point(&range.end, &snapshot);
 4186                            let start_point = TP::to_point(&range.start, &snapshot);
 4187                            (start_point..end_point, text)
 4188                        })
 4189                        .sorted_by_key(|(range, _)| range.start);
 4190                    buffer.edit(edits, None, cx);
 4191                })
 4192            }
 4193            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4194            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4195            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4196            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4197                .zip(new_selection_deltas)
 4198                .map(|(selection, delta)| Selection {
 4199                    id: selection.id,
 4200                    start: selection.start + delta,
 4201                    end: selection.end + delta,
 4202                    reversed: selection.reversed,
 4203                    goal: SelectionGoal::None,
 4204                })
 4205                .collect::<Vec<_>>();
 4206
 4207            let mut i = 0;
 4208            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4209                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4210                let start = map.buffer_snapshot.anchor_before(position);
 4211                let end = map.buffer_snapshot.anchor_after(position);
 4212                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4213                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4214                        Ordering::Less => i += 1,
 4215                        Ordering::Greater => break,
 4216                        Ordering::Equal => {
 4217                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4218                                Ordering::Less => i += 1,
 4219                                Ordering::Equal => break,
 4220                                Ordering::Greater => break,
 4221                            }
 4222                        }
 4223                    }
 4224                }
 4225                this.autoclose_regions.insert(
 4226                    i,
 4227                    AutocloseRegion {
 4228                        selection_id,
 4229                        range: start..end,
 4230                        pair,
 4231                    },
 4232                );
 4233            }
 4234
 4235            let had_active_inline_completion = this.has_active_inline_completion();
 4236            this.change_selections(
 4237                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4238                window,
 4239                cx,
 4240                |s| s.select(new_selections),
 4241            );
 4242
 4243            if !bracket_inserted {
 4244                if let Some(on_type_format_task) =
 4245                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4246                {
 4247                    on_type_format_task.detach_and_log_err(cx);
 4248                }
 4249            }
 4250
 4251            let editor_settings = EditorSettings::get_global(cx);
 4252            if bracket_inserted
 4253                && (editor_settings.auto_signature_help
 4254                    || editor_settings.show_signature_help_after_edits)
 4255            {
 4256                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4257            }
 4258
 4259            let trigger_in_words =
 4260                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4261            if this.hard_wrap.is_some() {
 4262                let latest: Range<Point> = this.selections.newest(cx).range();
 4263                if latest.is_empty()
 4264                    && this
 4265                        .buffer()
 4266                        .read(cx)
 4267                        .snapshot(cx)
 4268                        .line_len(MultiBufferRow(latest.start.row))
 4269                        == latest.start.column
 4270                {
 4271                    this.rewrap_impl(
 4272                        RewrapOptions {
 4273                            override_language_settings: true,
 4274                            preserve_existing_whitespace: true,
 4275                        },
 4276                        cx,
 4277                    )
 4278                }
 4279            }
 4280            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4281            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4282            this.refresh_inline_completion(true, false, window, cx);
 4283            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4284        });
 4285    }
 4286
 4287    fn find_possible_emoji_shortcode_at_position(
 4288        snapshot: &MultiBufferSnapshot,
 4289        position: Point,
 4290    ) -> Option<String> {
 4291        let mut chars = Vec::new();
 4292        let mut found_colon = false;
 4293        for char in snapshot.reversed_chars_at(position).take(100) {
 4294            // Found a possible emoji shortcode in the middle of the buffer
 4295            if found_colon {
 4296                if char.is_whitespace() {
 4297                    chars.reverse();
 4298                    return Some(chars.iter().collect());
 4299                }
 4300                // If the previous character is not a whitespace, we are in the middle of a word
 4301                // and we only want to complete the shortcode if the word is made up of other emojis
 4302                let mut containing_word = String::new();
 4303                for ch in snapshot
 4304                    .reversed_chars_at(position)
 4305                    .skip(chars.len() + 1)
 4306                    .take(100)
 4307                {
 4308                    if ch.is_whitespace() {
 4309                        break;
 4310                    }
 4311                    containing_word.push(ch);
 4312                }
 4313                let containing_word = containing_word.chars().rev().collect::<String>();
 4314                if util::word_consists_of_emojis(containing_word.as_str()) {
 4315                    chars.reverse();
 4316                    return Some(chars.iter().collect());
 4317                }
 4318            }
 4319
 4320            if char.is_whitespace() || !char.is_ascii() {
 4321                return None;
 4322            }
 4323            if char == ':' {
 4324                found_colon = true;
 4325            } else {
 4326                chars.push(char);
 4327            }
 4328        }
 4329        // Found a possible emoji shortcode at the beginning of the buffer
 4330        chars.reverse();
 4331        Some(chars.iter().collect())
 4332    }
 4333
 4334    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4335        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4336        self.transact(window, cx, |this, window, cx| {
 4337            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4338                let selections = this.selections.all::<usize>(cx);
 4339                let multi_buffer = this.buffer.read(cx);
 4340                let buffer = multi_buffer.snapshot(cx);
 4341                selections
 4342                    .iter()
 4343                    .map(|selection| {
 4344                        let start_point = selection.start.to_point(&buffer);
 4345                        let mut existing_indent =
 4346                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4347                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4348                        let start = selection.start;
 4349                        let end = selection.end;
 4350                        let selection_is_empty = start == end;
 4351                        let language_scope = buffer.language_scope_at(start);
 4352                        let (
 4353                            comment_delimiter,
 4354                            doc_delimiter,
 4355                            insert_extra_newline,
 4356                            indent_on_newline,
 4357                            indent_on_extra_newline,
 4358                        ) = if let Some(language) = &language_scope {
 4359                            let mut insert_extra_newline =
 4360                                insert_extra_newline_brackets(&buffer, start..end, language)
 4361                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4362
 4363                            // Comment extension on newline is allowed only for cursor selections
 4364                            let comment_delimiter = maybe!({
 4365                                if !selection_is_empty {
 4366                                    return None;
 4367                                }
 4368
 4369                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4370                                    return None;
 4371                                }
 4372
 4373                                let delimiters = language.line_comment_prefixes();
 4374                                let max_len_of_delimiter =
 4375                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4376                                let (snapshot, range) =
 4377                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4378
 4379                                let num_of_whitespaces = snapshot
 4380                                    .chars_for_range(range.clone())
 4381                                    .take_while(|c| c.is_whitespace())
 4382                                    .count();
 4383                                let comment_candidate = snapshot
 4384                                    .chars_for_range(range)
 4385                                    .skip(num_of_whitespaces)
 4386                                    .take(max_len_of_delimiter)
 4387                                    .collect::<String>();
 4388                                let (delimiter, trimmed_len) = delimiters
 4389                                    .iter()
 4390                                    .filter_map(|delimiter| {
 4391                                        let prefix = delimiter.trim_end();
 4392                                        if comment_candidate.starts_with(prefix) {
 4393                                            Some((delimiter, prefix.len()))
 4394                                        } else {
 4395                                            None
 4396                                        }
 4397                                    })
 4398                                    .max_by_key(|(_, len)| *len)?;
 4399
 4400                                let cursor_is_placed_after_comment_marker =
 4401                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4402                                if cursor_is_placed_after_comment_marker {
 4403                                    Some(delimiter.clone())
 4404                                } else {
 4405                                    None
 4406                                }
 4407                            });
 4408
 4409                            let mut indent_on_newline = IndentSize::spaces(0);
 4410                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4411
 4412                            let doc_delimiter = maybe!({
 4413                                if !selection_is_empty {
 4414                                    return None;
 4415                                }
 4416
 4417                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4418                                    return None;
 4419                                }
 4420
 4421                                let DocumentationConfig {
 4422                                    start: start_tag,
 4423                                    end: end_tag,
 4424                                    prefix: delimiter,
 4425                                    tab_size: len,
 4426                                } = language.documentation()?;
 4427
 4428                                let is_within_block_comment = buffer
 4429                                    .language_scope_at(start_point)
 4430                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4431                                if !is_within_block_comment {
 4432                                    return None;
 4433                                }
 4434
 4435                                let (snapshot, range) =
 4436                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4437
 4438                                let num_of_whitespaces = snapshot
 4439                                    .chars_for_range(range.clone())
 4440                                    .take_while(|c| c.is_whitespace())
 4441                                    .count();
 4442
 4443                                // 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.
 4444                                let column = start_point.column;
 4445                                let cursor_is_after_start_tag = {
 4446                                    let start_tag_len = start_tag.len();
 4447                                    let start_tag_line = snapshot
 4448                                        .chars_for_range(range.clone())
 4449                                        .skip(num_of_whitespaces)
 4450                                        .take(start_tag_len)
 4451                                        .collect::<String>();
 4452                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4453                                        num_of_whitespaces + start_tag_len <= column as usize
 4454                                    } else {
 4455                                        false
 4456                                    }
 4457                                };
 4458
 4459                                let cursor_is_after_delimiter = {
 4460                                    let delimiter_trim = delimiter.trim_end();
 4461                                    let delimiter_line = snapshot
 4462                                        .chars_for_range(range.clone())
 4463                                        .skip(num_of_whitespaces)
 4464                                        .take(delimiter_trim.len())
 4465                                        .collect::<String>();
 4466                                    if delimiter_line.starts_with(delimiter_trim) {
 4467                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4468                                    } else {
 4469                                        false
 4470                                    }
 4471                                };
 4472
 4473                                let cursor_is_before_end_tag_if_exists = {
 4474                                    let mut char_position = 0u32;
 4475                                    let mut end_tag_offset = None;
 4476
 4477                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4478                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4479                                            let chars_before_match =
 4480                                                chunk[..byte_pos].chars().count() as u32;
 4481                                            end_tag_offset =
 4482                                                Some(char_position + chars_before_match);
 4483                                            break 'outer;
 4484                                        }
 4485                                        char_position += chunk.chars().count() as u32;
 4486                                    }
 4487
 4488                                    if let Some(end_tag_offset) = end_tag_offset {
 4489                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4490                                        if cursor_is_after_start_tag {
 4491                                            if cursor_is_before_end_tag {
 4492                                                insert_extra_newline = true;
 4493                                            }
 4494                                            let cursor_is_at_start_of_end_tag =
 4495                                                column == end_tag_offset;
 4496                                            if cursor_is_at_start_of_end_tag {
 4497                                                indent_on_extra_newline.len = (*len).into();
 4498                                            }
 4499                                        }
 4500                                        cursor_is_before_end_tag
 4501                                    } else {
 4502                                        true
 4503                                    }
 4504                                };
 4505
 4506                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4507                                    && cursor_is_before_end_tag_if_exists
 4508                                {
 4509                                    if cursor_is_after_start_tag {
 4510                                        indent_on_newline.len = (*len).into();
 4511                                    }
 4512                                    Some(delimiter.clone())
 4513                                } else {
 4514                                    None
 4515                                }
 4516                            });
 4517
 4518                            (
 4519                                comment_delimiter,
 4520                                doc_delimiter,
 4521                                insert_extra_newline,
 4522                                indent_on_newline,
 4523                                indent_on_extra_newline,
 4524                            )
 4525                        } else {
 4526                            (
 4527                                None,
 4528                                None,
 4529                                false,
 4530                                IndentSize::default(),
 4531                                IndentSize::default(),
 4532                            )
 4533                        };
 4534
 4535                        let prevent_auto_indent = doc_delimiter.is_some();
 4536                        let delimiter = comment_delimiter.or(doc_delimiter);
 4537
 4538                        let capacity_for_delimiter =
 4539                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4540                        let mut new_text = String::with_capacity(
 4541                            1 + capacity_for_delimiter
 4542                                + existing_indent.len as usize
 4543                                + indent_on_newline.len as usize
 4544                                + indent_on_extra_newline.len as usize,
 4545                        );
 4546                        new_text.push('\n');
 4547                        new_text.extend(existing_indent.chars());
 4548                        new_text.extend(indent_on_newline.chars());
 4549
 4550                        if let Some(delimiter) = &delimiter {
 4551                            new_text.push_str(delimiter);
 4552                        }
 4553
 4554                        if insert_extra_newline {
 4555                            new_text.push('\n');
 4556                            new_text.extend(existing_indent.chars());
 4557                            new_text.extend(indent_on_extra_newline.chars());
 4558                        }
 4559
 4560                        let anchor = buffer.anchor_after(end);
 4561                        let new_selection = selection.map(|_| anchor);
 4562                        (
 4563                            ((start..end, new_text), prevent_auto_indent),
 4564                            (insert_extra_newline, new_selection),
 4565                        )
 4566                    })
 4567                    .unzip()
 4568            };
 4569
 4570            let mut auto_indent_edits = Vec::new();
 4571            let mut edits = Vec::new();
 4572            for (edit, prevent_auto_indent) in edits_with_flags {
 4573                if prevent_auto_indent {
 4574                    edits.push(edit);
 4575                } else {
 4576                    auto_indent_edits.push(edit);
 4577                }
 4578            }
 4579            if !edits.is_empty() {
 4580                this.edit(edits, cx);
 4581            }
 4582            if !auto_indent_edits.is_empty() {
 4583                this.edit_with_autoindent(auto_indent_edits, cx);
 4584            }
 4585
 4586            let buffer = this.buffer.read(cx).snapshot(cx);
 4587            let new_selections = selection_info
 4588                .into_iter()
 4589                .map(|(extra_newline_inserted, new_selection)| {
 4590                    let mut cursor = new_selection.end.to_point(&buffer);
 4591                    if extra_newline_inserted {
 4592                        cursor.row -= 1;
 4593                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4594                    }
 4595                    new_selection.map(|_| cursor)
 4596                })
 4597                .collect();
 4598
 4599            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4600            this.refresh_inline_completion(true, false, window, cx);
 4601        });
 4602    }
 4603
 4604    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4605        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4606
 4607        let buffer = self.buffer.read(cx);
 4608        let snapshot = buffer.snapshot(cx);
 4609
 4610        let mut edits = Vec::new();
 4611        let mut rows = Vec::new();
 4612
 4613        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4614            let cursor = selection.head();
 4615            let row = cursor.row;
 4616
 4617            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4618
 4619            let newline = "\n".to_string();
 4620            edits.push((start_of_line..start_of_line, newline));
 4621
 4622            rows.push(row + rows_inserted as u32);
 4623        }
 4624
 4625        self.transact(window, cx, |editor, window, cx| {
 4626            editor.edit(edits, cx);
 4627
 4628            editor.change_selections(Default::default(), window, cx, |s| {
 4629                let mut index = 0;
 4630                s.move_cursors_with(|map, _, _| {
 4631                    let row = rows[index];
 4632                    index += 1;
 4633
 4634                    let point = Point::new(row, 0);
 4635                    let boundary = map.next_line_boundary(point).1;
 4636                    let clipped = map.clip_point(boundary, Bias::Left);
 4637
 4638                    (clipped, SelectionGoal::None)
 4639                });
 4640            });
 4641
 4642            let mut indent_edits = Vec::new();
 4643            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4644            for row in rows {
 4645                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4646                for (row, indent) in indents {
 4647                    if indent.len == 0 {
 4648                        continue;
 4649                    }
 4650
 4651                    let text = match indent.kind {
 4652                        IndentKind::Space => " ".repeat(indent.len as usize),
 4653                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4654                    };
 4655                    let point = Point::new(row.0, 0);
 4656                    indent_edits.push((point..point, text));
 4657                }
 4658            }
 4659            editor.edit(indent_edits, cx);
 4660        });
 4661    }
 4662
 4663    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4664        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4665
 4666        let buffer = self.buffer.read(cx);
 4667        let snapshot = buffer.snapshot(cx);
 4668
 4669        let mut edits = Vec::new();
 4670        let mut rows = Vec::new();
 4671        let mut rows_inserted = 0;
 4672
 4673        for selection in self.selections.all_adjusted(cx) {
 4674            let cursor = selection.head();
 4675            let row = cursor.row;
 4676
 4677            let point = Point::new(row + 1, 0);
 4678            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4679
 4680            let newline = "\n".to_string();
 4681            edits.push((start_of_line..start_of_line, newline));
 4682
 4683            rows_inserted += 1;
 4684            rows.push(row + rows_inserted);
 4685        }
 4686
 4687        self.transact(window, cx, |editor, window, cx| {
 4688            editor.edit(edits, cx);
 4689
 4690            editor.change_selections(Default::default(), window, cx, |s| {
 4691                let mut index = 0;
 4692                s.move_cursors_with(|map, _, _| {
 4693                    let row = rows[index];
 4694                    index += 1;
 4695
 4696                    let point = Point::new(row, 0);
 4697                    let boundary = map.next_line_boundary(point).1;
 4698                    let clipped = map.clip_point(boundary, Bias::Left);
 4699
 4700                    (clipped, SelectionGoal::None)
 4701                });
 4702            });
 4703
 4704            let mut indent_edits = Vec::new();
 4705            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4706            for row in rows {
 4707                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4708                for (row, indent) in indents {
 4709                    if indent.len == 0 {
 4710                        continue;
 4711                    }
 4712
 4713                    let text = match indent.kind {
 4714                        IndentKind::Space => " ".repeat(indent.len as usize),
 4715                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4716                    };
 4717                    let point = Point::new(row.0, 0);
 4718                    indent_edits.push((point..point, text));
 4719                }
 4720            }
 4721            editor.edit(indent_edits, cx);
 4722        });
 4723    }
 4724
 4725    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4726        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4727            original_indent_columns: Vec::new(),
 4728        });
 4729        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4730    }
 4731
 4732    fn insert_with_autoindent_mode(
 4733        &mut self,
 4734        text: &str,
 4735        autoindent_mode: Option<AutoindentMode>,
 4736        window: &mut Window,
 4737        cx: &mut Context<Self>,
 4738    ) {
 4739        if self.read_only(cx) {
 4740            return;
 4741        }
 4742
 4743        let text: Arc<str> = text.into();
 4744        self.transact(window, cx, |this, window, cx| {
 4745            let old_selections = this.selections.all_adjusted(cx);
 4746            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4747                let anchors = {
 4748                    let snapshot = buffer.read(cx);
 4749                    old_selections
 4750                        .iter()
 4751                        .map(|s| {
 4752                            let anchor = snapshot.anchor_after(s.head());
 4753                            s.map(|_| anchor)
 4754                        })
 4755                        .collect::<Vec<_>>()
 4756                };
 4757                buffer.edit(
 4758                    old_selections
 4759                        .iter()
 4760                        .map(|s| (s.start..s.end, text.clone())),
 4761                    autoindent_mode,
 4762                    cx,
 4763                );
 4764                anchors
 4765            });
 4766
 4767            this.change_selections(Default::default(), window, cx, |s| {
 4768                s.select_anchors(selection_anchors);
 4769            });
 4770
 4771            cx.notify();
 4772        });
 4773    }
 4774
 4775    fn trigger_completion_on_input(
 4776        &mut self,
 4777        text: &str,
 4778        trigger_in_words: bool,
 4779        window: &mut Window,
 4780        cx: &mut Context<Self>,
 4781    ) {
 4782        let completions_source = self
 4783            .context_menu
 4784            .borrow()
 4785            .as_ref()
 4786            .and_then(|menu| match menu {
 4787                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4788                CodeContextMenu::CodeActions(_) => None,
 4789            });
 4790
 4791        match completions_source {
 4792            Some(CompletionsMenuSource::Words) => {
 4793                self.show_word_completions(&ShowWordCompletions, window, cx)
 4794            }
 4795            Some(CompletionsMenuSource::Normal)
 4796            | Some(CompletionsMenuSource::SnippetChoices)
 4797            | None
 4798                if self.is_completion_trigger(
 4799                    text,
 4800                    trigger_in_words,
 4801                    completions_source.is_some(),
 4802                    cx,
 4803                ) =>
 4804            {
 4805                self.show_completions(
 4806                    &ShowCompletions {
 4807                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4808                    },
 4809                    window,
 4810                    cx,
 4811                )
 4812            }
 4813            _ => {
 4814                self.hide_context_menu(window, cx);
 4815            }
 4816        }
 4817    }
 4818
 4819    fn is_completion_trigger(
 4820        &self,
 4821        text: &str,
 4822        trigger_in_words: bool,
 4823        menu_is_open: bool,
 4824        cx: &mut Context<Self>,
 4825    ) -> bool {
 4826        let position = self.selections.newest_anchor().head();
 4827        let multibuffer = self.buffer.read(cx);
 4828        let Some(buffer) = position
 4829            .buffer_id
 4830            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4831        else {
 4832            return false;
 4833        };
 4834
 4835        if let Some(completion_provider) = &self.completion_provider {
 4836            completion_provider.is_completion_trigger(
 4837                &buffer,
 4838                position.text_anchor,
 4839                text,
 4840                trigger_in_words,
 4841                menu_is_open,
 4842                cx,
 4843            )
 4844        } else {
 4845            false
 4846        }
 4847    }
 4848
 4849    /// If any empty selections is touching the start of its innermost containing autoclose
 4850    /// region, expand it to select the brackets.
 4851    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4852        let selections = self.selections.all::<usize>(cx);
 4853        let buffer = self.buffer.read(cx).read(cx);
 4854        let new_selections = self
 4855            .selections_with_autoclose_regions(selections, &buffer)
 4856            .map(|(mut selection, region)| {
 4857                if !selection.is_empty() {
 4858                    return selection;
 4859                }
 4860
 4861                if let Some(region) = region {
 4862                    let mut range = region.range.to_offset(&buffer);
 4863                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4864                        range.start -= region.pair.start.len();
 4865                        if buffer.contains_str_at(range.start, &region.pair.start)
 4866                            && buffer.contains_str_at(range.end, &region.pair.end)
 4867                        {
 4868                            range.end += region.pair.end.len();
 4869                            selection.start = range.start;
 4870                            selection.end = range.end;
 4871
 4872                            return selection;
 4873                        }
 4874                    }
 4875                }
 4876
 4877                let always_treat_brackets_as_autoclosed = buffer
 4878                    .language_settings_at(selection.start, cx)
 4879                    .always_treat_brackets_as_autoclosed;
 4880
 4881                if !always_treat_brackets_as_autoclosed {
 4882                    return selection;
 4883                }
 4884
 4885                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4886                    for (pair, enabled) in scope.brackets() {
 4887                        if !enabled || !pair.close {
 4888                            continue;
 4889                        }
 4890
 4891                        if buffer.contains_str_at(selection.start, &pair.end) {
 4892                            let pair_start_len = pair.start.len();
 4893                            if buffer.contains_str_at(
 4894                                selection.start.saturating_sub(pair_start_len),
 4895                                &pair.start,
 4896                            ) {
 4897                                selection.start -= pair_start_len;
 4898                                selection.end += pair.end.len();
 4899
 4900                                return selection;
 4901                            }
 4902                        }
 4903                    }
 4904                }
 4905
 4906                selection
 4907            })
 4908            .collect();
 4909
 4910        drop(buffer);
 4911        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4912            selections.select(new_selections)
 4913        });
 4914    }
 4915
 4916    /// Iterate the given selections, and for each one, find the smallest surrounding
 4917    /// autoclose region. This uses the ordering of the selections and the autoclose
 4918    /// regions to avoid repeated comparisons.
 4919    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4920        &'a self,
 4921        selections: impl IntoIterator<Item = Selection<D>>,
 4922        buffer: &'a MultiBufferSnapshot,
 4923    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4924        let mut i = 0;
 4925        let mut regions = self.autoclose_regions.as_slice();
 4926        selections.into_iter().map(move |selection| {
 4927            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4928
 4929            let mut enclosing = None;
 4930            while let Some(pair_state) = regions.get(i) {
 4931                if pair_state.range.end.to_offset(buffer) < range.start {
 4932                    regions = &regions[i + 1..];
 4933                    i = 0;
 4934                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4935                    break;
 4936                } else {
 4937                    if pair_state.selection_id == selection.id {
 4938                        enclosing = Some(pair_state);
 4939                    }
 4940                    i += 1;
 4941                }
 4942            }
 4943
 4944            (selection, enclosing)
 4945        })
 4946    }
 4947
 4948    /// Remove any autoclose regions that no longer contain their selection.
 4949    fn invalidate_autoclose_regions(
 4950        &mut self,
 4951        mut selections: &[Selection<Anchor>],
 4952        buffer: &MultiBufferSnapshot,
 4953    ) {
 4954        self.autoclose_regions.retain(|state| {
 4955            let mut i = 0;
 4956            while let Some(selection) = selections.get(i) {
 4957                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4958                    selections = &selections[1..];
 4959                    continue;
 4960                }
 4961                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4962                    break;
 4963                }
 4964                if selection.id == state.selection_id {
 4965                    return true;
 4966                } else {
 4967                    i += 1;
 4968                }
 4969            }
 4970            false
 4971        });
 4972    }
 4973
 4974    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4975        let offset = position.to_offset(buffer);
 4976        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4977        if offset > word_range.start && kind == Some(CharKind::Word) {
 4978            Some(
 4979                buffer
 4980                    .text_for_range(word_range.start..offset)
 4981                    .collect::<String>(),
 4982            )
 4983        } else {
 4984            None
 4985        }
 4986    }
 4987
 4988    pub fn toggle_inline_values(
 4989        &mut self,
 4990        _: &ToggleInlineValues,
 4991        _: &mut Window,
 4992        cx: &mut Context<Self>,
 4993    ) {
 4994        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4995
 4996        self.refresh_inline_values(cx);
 4997    }
 4998
 4999    pub fn toggle_inlay_hints(
 5000        &mut self,
 5001        _: &ToggleInlayHints,
 5002        _: &mut Window,
 5003        cx: &mut Context<Self>,
 5004    ) {
 5005        self.refresh_inlay_hints(
 5006            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5007            cx,
 5008        );
 5009    }
 5010
 5011    pub fn inlay_hints_enabled(&self) -> bool {
 5012        self.inlay_hint_cache.enabled
 5013    }
 5014
 5015    pub fn inline_values_enabled(&self) -> bool {
 5016        self.inline_value_cache.enabled
 5017    }
 5018
 5019    #[cfg(any(test, feature = "test-support"))]
 5020    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5021        self.display_map
 5022            .read(cx)
 5023            .current_inlays()
 5024            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5025            .cloned()
 5026            .collect()
 5027    }
 5028
 5029    #[cfg(any(test, feature = "test-support"))]
 5030    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5031        self.display_map
 5032            .read(cx)
 5033            .current_inlays()
 5034            .cloned()
 5035            .collect()
 5036    }
 5037
 5038    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5039        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5040            return;
 5041        }
 5042
 5043        let reason_description = reason.description();
 5044        let ignore_debounce = matches!(
 5045            reason,
 5046            InlayHintRefreshReason::SettingsChange(_)
 5047                | InlayHintRefreshReason::Toggle(_)
 5048                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5049                | InlayHintRefreshReason::ModifiersChanged(_)
 5050        );
 5051        let (invalidate_cache, required_languages) = match reason {
 5052            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5053                match self.inlay_hint_cache.modifiers_override(enabled) {
 5054                    Some(enabled) => {
 5055                        if enabled {
 5056                            (InvalidationStrategy::RefreshRequested, None)
 5057                        } else {
 5058                            self.splice_inlays(
 5059                                &self
 5060                                    .visible_inlay_hints(cx)
 5061                                    .iter()
 5062                                    .map(|inlay| inlay.id)
 5063                                    .collect::<Vec<InlayId>>(),
 5064                                Vec::new(),
 5065                                cx,
 5066                            );
 5067                            return;
 5068                        }
 5069                    }
 5070                    None => return,
 5071                }
 5072            }
 5073            InlayHintRefreshReason::Toggle(enabled) => {
 5074                if self.inlay_hint_cache.toggle(enabled) {
 5075                    if enabled {
 5076                        (InvalidationStrategy::RefreshRequested, None)
 5077                    } else {
 5078                        self.splice_inlays(
 5079                            &self
 5080                                .visible_inlay_hints(cx)
 5081                                .iter()
 5082                                .map(|inlay| inlay.id)
 5083                                .collect::<Vec<InlayId>>(),
 5084                            Vec::new(),
 5085                            cx,
 5086                        );
 5087                        return;
 5088                    }
 5089                } else {
 5090                    return;
 5091                }
 5092            }
 5093            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5094                match self.inlay_hint_cache.update_settings(
 5095                    &self.buffer,
 5096                    new_settings,
 5097                    self.visible_inlay_hints(cx),
 5098                    cx,
 5099                ) {
 5100                    ControlFlow::Break(Some(InlaySplice {
 5101                        to_remove,
 5102                        to_insert,
 5103                    })) => {
 5104                        self.splice_inlays(&to_remove, to_insert, cx);
 5105                        return;
 5106                    }
 5107                    ControlFlow::Break(None) => return,
 5108                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5109                }
 5110            }
 5111            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5112                if let Some(InlaySplice {
 5113                    to_remove,
 5114                    to_insert,
 5115                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5116                {
 5117                    self.splice_inlays(&to_remove, to_insert, cx);
 5118                }
 5119                self.display_map.update(cx, |display_map, _| {
 5120                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5121                });
 5122                return;
 5123            }
 5124            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5125            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5126                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5127            }
 5128            InlayHintRefreshReason::RefreshRequested => {
 5129                (InvalidationStrategy::RefreshRequested, None)
 5130            }
 5131        };
 5132
 5133        if let Some(InlaySplice {
 5134            to_remove,
 5135            to_insert,
 5136        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5137            reason_description,
 5138            self.visible_excerpts(required_languages.as_ref(), cx),
 5139            invalidate_cache,
 5140            ignore_debounce,
 5141            cx,
 5142        ) {
 5143            self.splice_inlays(&to_remove, to_insert, cx);
 5144        }
 5145    }
 5146
 5147    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5148        self.display_map
 5149            .read(cx)
 5150            .current_inlays()
 5151            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5152            .cloned()
 5153            .collect()
 5154    }
 5155
 5156    pub fn visible_excerpts(
 5157        &self,
 5158        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5159        cx: &mut Context<Editor>,
 5160    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5161        let Some(project) = self.project.as_ref() else {
 5162            return HashMap::default();
 5163        };
 5164        let project = project.read(cx);
 5165        let multi_buffer = self.buffer().read(cx);
 5166        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5167        let multi_buffer_visible_start = self
 5168            .scroll_manager
 5169            .anchor()
 5170            .anchor
 5171            .to_point(&multi_buffer_snapshot);
 5172        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5173            multi_buffer_visible_start
 5174                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5175            Bias::Left,
 5176        );
 5177        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5178        multi_buffer_snapshot
 5179            .range_to_buffer_ranges(multi_buffer_visible_range)
 5180            .into_iter()
 5181            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5182            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5183                let buffer_file = project::File::from_dyn(buffer.file())?;
 5184                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5185                let worktree_entry = buffer_worktree
 5186                    .read(cx)
 5187                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5188                if worktree_entry.is_ignored {
 5189                    return None;
 5190                }
 5191
 5192                let language = buffer.language()?;
 5193                if let Some(restrict_to_languages) = restrict_to_languages {
 5194                    if !restrict_to_languages.contains(language) {
 5195                        return None;
 5196                    }
 5197                }
 5198                Some((
 5199                    excerpt_id,
 5200                    (
 5201                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5202                        buffer.version().clone(),
 5203                        excerpt_visible_range,
 5204                    ),
 5205                ))
 5206            })
 5207            .collect()
 5208    }
 5209
 5210    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5211        TextLayoutDetails {
 5212            text_system: window.text_system().clone(),
 5213            editor_style: self.style.clone().unwrap(),
 5214            rem_size: window.rem_size(),
 5215            scroll_anchor: self.scroll_manager.anchor(),
 5216            visible_rows: self.visible_line_count(),
 5217            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5218        }
 5219    }
 5220
 5221    pub fn splice_inlays(
 5222        &self,
 5223        to_remove: &[InlayId],
 5224        to_insert: Vec<Inlay>,
 5225        cx: &mut Context<Self>,
 5226    ) {
 5227        self.display_map.update(cx, |display_map, cx| {
 5228            display_map.splice_inlays(to_remove, to_insert, cx)
 5229        });
 5230        cx.notify();
 5231    }
 5232
 5233    fn trigger_on_type_formatting(
 5234        &self,
 5235        input: String,
 5236        window: &mut Window,
 5237        cx: &mut Context<Self>,
 5238    ) -> Option<Task<Result<()>>> {
 5239        if input.len() != 1 {
 5240            return None;
 5241        }
 5242
 5243        let project = self.project.as_ref()?;
 5244        let position = self.selections.newest_anchor().head();
 5245        let (buffer, buffer_position) = self
 5246            .buffer
 5247            .read(cx)
 5248            .text_anchor_for_position(position, cx)?;
 5249
 5250        let settings = language_settings::language_settings(
 5251            buffer
 5252                .read(cx)
 5253                .language_at(buffer_position)
 5254                .map(|l| l.name()),
 5255            buffer.read(cx).file(),
 5256            cx,
 5257        );
 5258        if !settings.use_on_type_format {
 5259            return None;
 5260        }
 5261
 5262        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5263        // hence we do LSP request & edit on host side only — add formats to host's history.
 5264        let push_to_lsp_host_history = true;
 5265        // If this is not the host, append its history with new edits.
 5266        let push_to_client_history = project.read(cx).is_via_collab();
 5267
 5268        let on_type_formatting = project.update(cx, |project, cx| {
 5269            project.on_type_format(
 5270                buffer.clone(),
 5271                buffer_position,
 5272                input,
 5273                push_to_lsp_host_history,
 5274                cx,
 5275            )
 5276        });
 5277        Some(cx.spawn_in(window, async move |editor, cx| {
 5278            if let Some(transaction) = on_type_formatting.await? {
 5279                if push_to_client_history {
 5280                    buffer
 5281                        .update(cx, |buffer, _| {
 5282                            buffer.push_transaction(transaction, Instant::now());
 5283                            buffer.finalize_last_transaction();
 5284                        })
 5285                        .ok();
 5286                }
 5287                editor.update(cx, |editor, cx| {
 5288                    editor.refresh_document_highlights(cx);
 5289                })?;
 5290            }
 5291            Ok(())
 5292        }))
 5293    }
 5294
 5295    pub fn show_word_completions(
 5296        &mut self,
 5297        _: &ShowWordCompletions,
 5298        window: &mut Window,
 5299        cx: &mut Context<Self>,
 5300    ) {
 5301        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5302    }
 5303
 5304    pub fn show_completions(
 5305        &mut self,
 5306        options: &ShowCompletions,
 5307        window: &mut Window,
 5308        cx: &mut Context<Self>,
 5309    ) {
 5310        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5311    }
 5312
 5313    fn open_or_update_completions_menu(
 5314        &mut self,
 5315        requested_source: Option<CompletionsMenuSource>,
 5316        trigger: Option<&str>,
 5317        window: &mut Window,
 5318        cx: &mut Context<Self>,
 5319    ) {
 5320        if self.pending_rename.is_some() {
 5321            return;
 5322        }
 5323
 5324        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5325
 5326        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5327        // inserted and selected. To handle that case, the start of the selection is used so that
 5328        // the menu starts with all choices.
 5329        let position = self
 5330            .selections
 5331            .newest_anchor()
 5332            .start
 5333            .bias_right(&multibuffer_snapshot);
 5334        if position.diff_base_anchor.is_some() {
 5335            return;
 5336        }
 5337        let (buffer, buffer_position) =
 5338            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5339                output
 5340            } else {
 5341                return;
 5342            };
 5343        let buffer_snapshot = buffer.read(cx).snapshot();
 5344
 5345        let query: Option<Arc<String>> =
 5346            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5347
 5348        drop(multibuffer_snapshot);
 5349
 5350        let provider = match requested_source {
 5351            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5352            Some(CompletionsMenuSource::Words) => None,
 5353            Some(CompletionsMenuSource::SnippetChoices) => {
 5354                log::error!("bug: SnippetChoices requested_source is not handled");
 5355                None
 5356            }
 5357        };
 5358
 5359        let sort_completions = provider
 5360            .as_ref()
 5361            .map_or(false, |provider| provider.sort_completions());
 5362
 5363        let filter_completions = provider
 5364            .as_ref()
 5365            .map_or(true, |provider| provider.filter_completions());
 5366
 5367        let trigger_kind = match trigger {
 5368            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5369                CompletionTriggerKind::TRIGGER_CHARACTER
 5370            }
 5371            _ => CompletionTriggerKind::INVOKED,
 5372        };
 5373        let completion_context = CompletionContext {
 5374            trigger_character: trigger.and_then(|trigger| {
 5375                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5376                    Some(String::from(trigger))
 5377                } else {
 5378                    None
 5379                }
 5380            }),
 5381            trigger_kind,
 5382        };
 5383
 5384        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5385        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5386        // involve trigger chars, so this is skipped in that case.
 5387        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5388        {
 5389            let menu_is_open = matches!(
 5390                self.context_menu.borrow().as_ref(),
 5391                Some(CodeContextMenu::Completions(_))
 5392            );
 5393            if menu_is_open {
 5394                self.hide_context_menu(window, cx);
 5395            }
 5396        }
 5397
 5398        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5399            if filter_completions {
 5400                menu.filter(query.clone(), provider.clone(), window, cx);
 5401            }
 5402            // When `is_incomplete` is false, no need to re-query completions when the current query
 5403            // is a suffix of the initial query.
 5404            if !menu.is_incomplete {
 5405                // If the new query is a suffix of the old query (typing more characters) and
 5406                // the previous result was complete, the existing completions can be filtered.
 5407                //
 5408                // Note that this is always true for snippet completions.
 5409                let query_matches = match (&menu.initial_query, &query) {
 5410                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5411                    (None, _) => true,
 5412                    _ => false,
 5413                };
 5414                if query_matches {
 5415                    let position_matches = if menu.initial_position == position {
 5416                        true
 5417                    } else {
 5418                        let snapshot = self.buffer.read(cx).read(cx);
 5419                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5420                    };
 5421                    if position_matches {
 5422                        return;
 5423                    }
 5424                }
 5425            }
 5426        };
 5427
 5428        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5429            buffer_snapshot.surrounding_word(buffer_position)
 5430        {
 5431            let word_to_exclude = buffer_snapshot
 5432                .text_for_range(word_range.clone())
 5433                .collect::<String>();
 5434            (
 5435                buffer_snapshot.anchor_before(word_range.start)
 5436                    ..buffer_snapshot.anchor_after(buffer_position),
 5437                Some(word_to_exclude),
 5438            )
 5439        } else {
 5440            (buffer_position..buffer_position, None)
 5441        };
 5442
 5443        let language = buffer_snapshot
 5444            .language_at(buffer_position)
 5445            .map(|language| language.name());
 5446
 5447        let completion_settings =
 5448            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5449
 5450        let show_completion_documentation = buffer_snapshot
 5451            .settings_at(buffer_position, cx)
 5452            .show_completion_documentation;
 5453
 5454        // The document can be large, so stay in reasonable bounds when searching for words,
 5455        // otherwise completion pop-up might be slow to appear.
 5456        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5457        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5458        let min_word_search = buffer_snapshot.clip_point(
 5459            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5460            Bias::Left,
 5461        );
 5462        let max_word_search = buffer_snapshot.clip_point(
 5463            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5464            Bias::Right,
 5465        );
 5466        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5467            ..buffer_snapshot.point_to_offset(max_word_search);
 5468
 5469        let skip_digits = query
 5470            .as_ref()
 5471            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5472
 5473        let (mut words, provider_responses) = match &provider {
 5474            Some(provider) => {
 5475                let provider_responses = provider.completions(
 5476                    position.excerpt_id,
 5477                    &buffer,
 5478                    buffer_position,
 5479                    completion_context,
 5480                    window,
 5481                    cx,
 5482                );
 5483
 5484                let words = match completion_settings.words {
 5485                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5486                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5487                        .background_spawn(async move {
 5488                            buffer_snapshot.words_in_range(WordsQuery {
 5489                                fuzzy_contents: None,
 5490                                range: word_search_range,
 5491                                skip_digits,
 5492                            })
 5493                        }),
 5494                };
 5495
 5496                (words, provider_responses)
 5497            }
 5498            None => (
 5499                cx.background_spawn(async move {
 5500                    buffer_snapshot.words_in_range(WordsQuery {
 5501                        fuzzy_contents: None,
 5502                        range: word_search_range,
 5503                        skip_digits,
 5504                    })
 5505                }),
 5506                Task::ready(Ok(Vec::new())),
 5507            ),
 5508        };
 5509
 5510        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5511
 5512        let id = post_inc(&mut self.next_completion_id);
 5513        let task = cx.spawn_in(window, async move |editor, cx| {
 5514            let Ok(()) = editor.update(cx, |this, _| {
 5515                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5516            }) else {
 5517                return;
 5518            };
 5519
 5520            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5521            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5522            let mut completions = Vec::new();
 5523            let mut is_incomplete = false;
 5524            if let Some(provider_responses) = provider_responses.await.log_err() {
 5525                if !provider_responses.is_empty() {
 5526                    for response in provider_responses {
 5527                        completions.extend(response.completions);
 5528                        is_incomplete = is_incomplete || response.is_incomplete;
 5529                    }
 5530                    if completion_settings.words == WordsCompletionMode::Fallback {
 5531                        words = Task::ready(BTreeMap::default());
 5532                    }
 5533                }
 5534            }
 5535
 5536            let mut words = words.await;
 5537            if let Some(word_to_exclude) = &word_to_exclude {
 5538                words.remove(word_to_exclude);
 5539            }
 5540            for lsp_completion in &completions {
 5541                words.remove(&lsp_completion.new_text);
 5542            }
 5543            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5544                replace_range: word_replace_range.clone(),
 5545                new_text: word.clone(),
 5546                label: CodeLabel::plain(word, None),
 5547                icon_path: None,
 5548                documentation: None,
 5549                source: CompletionSource::BufferWord {
 5550                    word_range,
 5551                    resolved: false,
 5552                },
 5553                insert_text_mode: Some(InsertTextMode::AS_IS),
 5554                confirm: None,
 5555            }));
 5556
 5557            let menu = if completions.is_empty() {
 5558                None
 5559            } else {
 5560                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5561                    let languages = editor
 5562                        .workspace
 5563                        .as_ref()
 5564                        .and_then(|(workspace, _)| workspace.upgrade())
 5565                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5566                    let menu = CompletionsMenu::new(
 5567                        id,
 5568                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5569                        sort_completions,
 5570                        show_completion_documentation,
 5571                        position,
 5572                        query.clone(),
 5573                        is_incomplete,
 5574                        buffer.clone(),
 5575                        completions.into(),
 5576                        snippet_sort_order,
 5577                        languages,
 5578                        language,
 5579                        cx,
 5580                    );
 5581
 5582                    let query = if filter_completions { query } else { None };
 5583                    let matches_task = if let Some(query) = query {
 5584                        menu.do_async_filtering(query, cx)
 5585                    } else {
 5586                        Task::ready(menu.unfiltered_matches())
 5587                    };
 5588                    (menu, matches_task)
 5589                }) else {
 5590                    return;
 5591                };
 5592
 5593                let matches = matches_task.await;
 5594
 5595                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5596                    // Newer menu already set, so exit.
 5597                    match editor.context_menu.borrow().as_ref() {
 5598                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5599                            if prev_menu.id > id {
 5600                                return;
 5601                            }
 5602                        }
 5603                        _ => {}
 5604                    };
 5605
 5606                    // Only valid to take prev_menu because it the new menu is immediately set
 5607                    // below, or the menu is hidden.
 5608                    match editor.context_menu.borrow_mut().take() {
 5609                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5610                            let position_matches =
 5611                                if prev_menu.initial_position == menu.initial_position {
 5612                                    true
 5613                                } else {
 5614                                    let snapshot = editor.buffer.read(cx).read(cx);
 5615                                    prev_menu.initial_position.to_offset(&snapshot)
 5616                                        == menu.initial_position.to_offset(&snapshot)
 5617                                };
 5618                            if position_matches {
 5619                                // Preserve markdown cache before `set_filter_results` because it will
 5620                                // try to populate the documentation cache.
 5621                                menu.preserve_markdown_cache(prev_menu);
 5622                            }
 5623                        }
 5624                        _ => {}
 5625                    };
 5626
 5627                    menu.set_filter_results(matches, provider, window, cx);
 5628                }) else {
 5629                    return;
 5630                };
 5631
 5632                menu.visible().then_some(menu)
 5633            };
 5634
 5635            editor
 5636                .update_in(cx, |editor, window, cx| {
 5637                    if editor.focus_handle.is_focused(window) {
 5638                        if let Some(menu) = menu {
 5639                            *editor.context_menu.borrow_mut() =
 5640                                Some(CodeContextMenu::Completions(menu));
 5641
 5642                            crate::hover_popover::hide_hover(editor, cx);
 5643                            if editor.show_edit_predictions_in_menu() {
 5644                                editor.update_visible_inline_completion(window, cx);
 5645                            } else {
 5646                                editor.discard_inline_completion(false, cx);
 5647                            }
 5648
 5649                            cx.notify();
 5650                            return;
 5651                        }
 5652                    }
 5653
 5654                    if editor.completion_tasks.len() <= 1 {
 5655                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5656                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5657                        // If it was already hidden and we don't show inline completions in the menu, we should
 5658                        // also show the inline-completion when available.
 5659                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5660                            editor.update_visible_inline_completion(window, cx);
 5661                        }
 5662                    }
 5663                })
 5664                .ok();
 5665        });
 5666
 5667        self.completion_tasks.push((id, task));
 5668    }
 5669
 5670    #[cfg(feature = "test-support")]
 5671    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5672        let menu = self.context_menu.borrow();
 5673        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5674            let completions = menu.completions.borrow();
 5675            Some(completions.to_vec())
 5676        } else {
 5677            None
 5678        }
 5679    }
 5680
 5681    pub fn with_completions_menu_matching_id<R>(
 5682        &self,
 5683        id: CompletionId,
 5684        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5685    ) -> R {
 5686        let mut context_menu = self.context_menu.borrow_mut();
 5687        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5688            return f(None);
 5689        };
 5690        if completions_menu.id != id {
 5691            return f(None);
 5692        }
 5693        f(Some(completions_menu))
 5694    }
 5695
 5696    pub fn confirm_completion(
 5697        &mut self,
 5698        action: &ConfirmCompletion,
 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::Complete, window, cx)
 5704    }
 5705
 5706    pub fn confirm_completion_insert(
 5707        &mut self,
 5708        _: &ConfirmCompletionInsert,
 5709        window: &mut Window,
 5710        cx: &mut Context<Self>,
 5711    ) -> Option<Task<Result<()>>> {
 5712        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5713        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5714    }
 5715
 5716    pub fn confirm_completion_replace(
 5717        &mut self,
 5718        _: &ConfirmCompletionReplace,
 5719        window: &mut Window,
 5720        cx: &mut Context<Self>,
 5721    ) -> Option<Task<Result<()>>> {
 5722        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5723        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5724    }
 5725
 5726    pub fn compose_completion(
 5727        &mut self,
 5728        action: &ComposeCompletion,
 5729        window: &mut Window,
 5730        cx: &mut Context<Self>,
 5731    ) -> Option<Task<Result<()>>> {
 5732        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5733        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5734    }
 5735
 5736    fn do_completion(
 5737        &mut self,
 5738        item_ix: Option<usize>,
 5739        intent: CompletionIntent,
 5740        window: &mut Window,
 5741        cx: &mut Context<Editor>,
 5742    ) -> Option<Task<Result<()>>> {
 5743        use language::ToOffset as _;
 5744
 5745        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5746        else {
 5747            return None;
 5748        };
 5749
 5750        let candidate_id = {
 5751            let entries = completions_menu.entries.borrow();
 5752            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5753            if self.show_edit_predictions_in_menu() {
 5754                self.discard_inline_completion(true, cx);
 5755            }
 5756            mat.candidate_id
 5757        };
 5758
 5759        let completion = completions_menu
 5760            .completions
 5761            .borrow()
 5762            .get(candidate_id)?
 5763            .clone();
 5764        cx.stop_propagation();
 5765
 5766        let buffer_handle = completions_menu.buffer.clone();
 5767
 5768        let CompletionEdit {
 5769            new_text,
 5770            snippet,
 5771            replace_range,
 5772        } = process_completion_for_edit(
 5773            &completion,
 5774            intent,
 5775            &buffer_handle,
 5776            &completions_menu.initial_position.text_anchor,
 5777            cx,
 5778        );
 5779
 5780        let buffer = buffer_handle.read(cx);
 5781        let snapshot = self.buffer.read(cx).snapshot(cx);
 5782        let newest_anchor = self.selections.newest_anchor();
 5783        let replace_range_multibuffer = {
 5784            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5785            let multibuffer_anchor = snapshot
 5786                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5787                .unwrap()
 5788                ..snapshot
 5789                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5790                    .unwrap();
 5791            multibuffer_anchor.start.to_offset(&snapshot)
 5792                ..multibuffer_anchor.end.to_offset(&snapshot)
 5793        };
 5794        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5795            return None;
 5796        }
 5797
 5798        let old_text = buffer
 5799            .text_for_range(replace_range.clone())
 5800            .collect::<String>();
 5801        let lookbehind = newest_anchor
 5802            .start
 5803            .text_anchor
 5804            .to_offset(buffer)
 5805            .saturating_sub(replace_range.start);
 5806        let lookahead = replace_range
 5807            .end
 5808            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5809        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5810        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5811
 5812        let selections = self.selections.all::<usize>(cx);
 5813        let mut ranges = Vec::new();
 5814        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5815
 5816        for selection in &selections {
 5817            let range = if selection.id == newest_anchor.id {
 5818                replace_range_multibuffer.clone()
 5819            } else {
 5820                let mut range = selection.range();
 5821
 5822                // if prefix is present, don't duplicate it
 5823                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5824                    range.start = range.start.saturating_sub(lookbehind);
 5825
 5826                    // if suffix is also present, mimic the newest cursor and replace it
 5827                    if selection.id != newest_anchor.id
 5828                        && snapshot.contains_str_at(range.end, suffix)
 5829                    {
 5830                        range.end += lookahead;
 5831                    }
 5832                }
 5833                range
 5834            };
 5835
 5836            ranges.push(range.clone());
 5837
 5838            if !self.linked_edit_ranges.is_empty() {
 5839                let start_anchor = snapshot.anchor_before(range.start);
 5840                let end_anchor = snapshot.anchor_after(range.end);
 5841                if let Some(ranges) = self
 5842                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5843                {
 5844                    for (buffer, edits) in ranges {
 5845                        linked_edits
 5846                            .entry(buffer.clone())
 5847                            .or_default()
 5848                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5849                    }
 5850                }
 5851            }
 5852        }
 5853
 5854        let common_prefix_len = old_text
 5855            .chars()
 5856            .zip(new_text.chars())
 5857            .take_while(|(a, b)| a == b)
 5858            .map(|(a, _)| a.len_utf8())
 5859            .sum::<usize>();
 5860
 5861        cx.emit(EditorEvent::InputHandled {
 5862            utf16_range_to_replace: None,
 5863            text: new_text[common_prefix_len..].into(),
 5864        });
 5865
 5866        self.transact(window, cx, |this, window, cx| {
 5867            if let Some(mut snippet) = snippet {
 5868                snippet.text = new_text.to_string();
 5869                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5870            } else {
 5871                this.buffer.update(cx, |buffer, cx| {
 5872                    let auto_indent = match completion.insert_text_mode {
 5873                        Some(InsertTextMode::AS_IS) => None,
 5874                        _ => this.autoindent_mode.clone(),
 5875                    };
 5876                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5877                    buffer.edit(edits, auto_indent, cx);
 5878                });
 5879            }
 5880            for (buffer, edits) in linked_edits {
 5881                buffer.update(cx, |buffer, cx| {
 5882                    let snapshot = buffer.snapshot();
 5883                    let edits = edits
 5884                        .into_iter()
 5885                        .map(|(range, text)| {
 5886                            use text::ToPoint as TP;
 5887                            let end_point = TP::to_point(&range.end, &snapshot);
 5888                            let start_point = TP::to_point(&range.start, &snapshot);
 5889                            (start_point..end_point, text)
 5890                        })
 5891                        .sorted_by_key(|(range, _)| range.start);
 5892                    buffer.edit(edits, None, cx);
 5893                })
 5894            }
 5895
 5896            this.refresh_inline_completion(true, false, window, cx);
 5897        });
 5898
 5899        let show_new_completions_on_confirm = completion
 5900            .confirm
 5901            .as_ref()
 5902            .map_or(false, |confirm| confirm(intent, window, cx));
 5903        if show_new_completions_on_confirm {
 5904            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5905        }
 5906
 5907        let provider = self.completion_provider.as_ref()?;
 5908        drop(completion);
 5909        let apply_edits = provider.apply_additional_edits_for_completion(
 5910            buffer_handle,
 5911            completions_menu.completions.clone(),
 5912            candidate_id,
 5913            true,
 5914            cx,
 5915        );
 5916
 5917        let editor_settings = EditorSettings::get_global(cx);
 5918        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5919            // After the code completion is finished, users often want to know what signatures are needed.
 5920            // so we should automatically call signature_help
 5921            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5922        }
 5923
 5924        Some(cx.foreground_executor().spawn(async move {
 5925            apply_edits.await?;
 5926            Ok(())
 5927        }))
 5928    }
 5929
 5930    pub fn toggle_code_actions(
 5931        &mut self,
 5932        action: &ToggleCodeActions,
 5933        window: &mut Window,
 5934        cx: &mut Context<Self>,
 5935    ) {
 5936        let quick_launch = action.quick_launch;
 5937        let mut context_menu = self.context_menu.borrow_mut();
 5938        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5939            if code_actions.deployed_from == action.deployed_from {
 5940                // Toggle if we're selecting the same one
 5941                *context_menu = None;
 5942                cx.notify();
 5943                return;
 5944            } else {
 5945                // Otherwise, clear it and start a new one
 5946                *context_menu = None;
 5947                cx.notify();
 5948            }
 5949        }
 5950        drop(context_menu);
 5951        let snapshot = self.snapshot(window, cx);
 5952        let deployed_from = action.deployed_from.clone();
 5953        let action = action.clone();
 5954        self.completion_tasks.clear();
 5955        self.discard_inline_completion(false, cx);
 5956
 5957        let multibuffer_point = match &action.deployed_from {
 5958            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5959                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5960            }
 5961            _ => self.selections.newest::<Point>(cx).head(),
 5962        };
 5963        let Some((buffer, buffer_row)) = snapshot
 5964            .buffer_snapshot
 5965            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5966            .and_then(|(buffer_snapshot, range)| {
 5967                self.buffer()
 5968                    .read(cx)
 5969                    .buffer(buffer_snapshot.remote_id())
 5970                    .map(|buffer| (buffer, range.start.row))
 5971            })
 5972        else {
 5973            return;
 5974        };
 5975        let buffer_id = buffer.read(cx).remote_id();
 5976        let tasks = self
 5977            .tasks
 5978            .get(&(buffer_id, buffer_row))
 5979            .map(|t| Arc::new(t.to_owned()));
 5980
 5981        if !self.focus_handle.is_focused(window) {
 5982            return;
 5983        }
 5984        let project = self.project.clone();
 5985
 5986        let code_actions_task = match deployed_from {
 5987            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5988            _ => self.code_actions(buffer_row, window, cx),
 5989        };
 5990
 5991        let runnable_task = match deployed_from {
 5992            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5993            _ => {
 5994                let mut task_context_task = Task::ready(None);
 5995                if let Some(tasks) = &tasks {
 5996                    if let Some(project) = project {
 5997                        task_context_task =
 5998                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5999                    }
 6000                }
 6001
 6002                cx.spawn_in(window, {
 6003                    let buffer = buffer.clone();
 6004                    async move |editor, cx| {
 6005                        let task_context = task_context_task.await;
 6006
 6007                        let resolved_tasks =
 6008                            tasks
 6009                                .zip(task_context.clone())
 6010                                .map(|(tasks, task_context)| ResolvedTasks {
 6011                                    templates: tasks.resolve(&task_context).collect(),
 6012                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6013                                        multibuffer_point.row,
 6014                                        tasks.column,
 6015                                    )),
 6016                                });
 6017                        let debug_scenarios = editor
 6018                            .update(cx, |editor, cx| {
 6019                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6020                            })?
 6021                            .await;
 6022                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6023                    }
 6024                })
 6025            }
 6026        };
 6027
 6028        cx.spawn_in(window, async move |editor, cx| {
 6029            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6030            let code_actions = code_actions_task.await;
 6031            let spawn_straight_away = quick_launch
 6032                && resolved_tasks
 6033                    .as_ref()
 6034                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6035                && code_actions
 6036                    .as_ref()
 6037                    .map_or(true, |actions| actions.is_empty())
 6038                && debug_scenarios.is_empty();
 6039
 6040            editor.update_in(cx, |editor, window, cx| {
 6041                crate::hover_popover::hide_hover(editor, cx);
 6042                let actions = CodeActionContents::new(
 6043                    resolved_tasks,
 6044                    code_actions,
 6045                    debug_scenarios,
 6046                    task_context.unwrap_or_default(),
 6047                );
 6048
 6049                // Don't show the menu if there are no actions available
 6050                if actions.is_empty() {
 6051                    cx.notify();
 6052                    return Task::ready(Ok(()));
 6053                }
 6054
 6055                *editor.context_menu.borrow_mut() =
 6056                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6057                        buffer,
 6058                        actions,
 6059                        selected_item: Default::default(),
 6060                        scroll_handle: UniformListScrollHandle::default(),
 6061                        deployed_from,
 6062                    }));
 6063                cx.notify();
 6064                if spawn_straight_away {
 6065                    if let Some(task) = editor.confirm_code_action(
 6066                        &ConfirmCodeAction { item_ix: Some(0) },
 6067                        window,
 6068                        cx,
 6069                    ) {
 6070                        return task;
 6071                    }
 6072                }
 6073
 6074                Task::ready(Ok(()))
 6075            })
 6076        })
 6077        .detach_and_log_err(cx);
 6078    }
 6079
 6080    fn debug_scenarios(
 6081        &mut self,
 6082        resolved_tasks: &Option<ResolvedTasks>,
 6083        buffer: &Entity<Buffer>,
 6084        cx: &mut App,
 6085    ) -> Task<Vec<task::DebugScenario>> {
 6086        maybe!({
 6087            let project = self.project.as_ref()?;
 6088            let dap_store = project.read(cx).dap_store();
 6089            let mut scenarios = vec![];
 6090            let resolved_tasks = resolved_tasks.as_ref()?;
 6091            let buffer = buffer.read(cx);
 6092            let language = buffer.language()?;
 6093            let file = buffer.file();
 6094            let debug_adapter = language_settings(language.name().into(), file, cx)
 6095                .debuggers
 6096                .first()
 6097                .map(SharedString::from)
 6098                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6099
 6100            dap_store.update(cx, |dap_store, cx| {
 6101                for (_, task) in &resolved_tasks.templates {
 6102                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6103                        task.original_task().clone(),
 6104                        debug_adapter.clone().into(),
 6105                        task.display_label().to_owned().into(),
 6106                        cx,
 6107                    );
 6108                    scenarios.push(maybe_scenario);
 6109                }
 6110            });
 6111            Some(cx.background_spawn(async move {
 6112                let scenarios = futures::future::join_all(scenarios)
 6113                    .await
 6114                    .into_iter()
 6115                    .flatten()
 6116                    .collect::<Vec<_>>();
 6117                scenarios
 6118            }))
 6119        })
 6120        .unwrap_or_else(|| Task::ready(vec![]))
 6121    }
 6122
 6123    fn code_actions(
 6124        &mut self,
 6125        buffer_row: u32,
 6126        window: &mut Window,
 6127        cx: &mut Context<Self>,
 6128    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6129        let mut task = self.code_actions_task.take();
 6130        cx.spawn_in(window, async move |editor, cx| {
 6131            while let Some(prev_task) = task {
 6132                prev_task.await.log_err();
 6133                task = editor
 6134                    .update(cx, |this, _| this.code_actions_task.take())
 6135                    .ok()?;
 6136            }
 6137
 6138            editor
 6139                .update(cx, |editor, cx| {
 6140                    editor
 6141                        .available_code_actions
 6142                        .clone()
 6143                        .and_then(|(location, code_actions)| {
 6144                            let snapshot = location.buffer.read(cx).snapshot();
 6145                            let point_range = location.range.to_point(&snapshot);
 6146                            let point_range = point_range.start.row..=point_range.end.row;
 6147                            if point_range.contains(&buffer_row) {
 6148                                Some(code_actions)
 6149                            } else {
 6150                                None
 6151                            }
 6152                        })
 6153                })
 6154                .ok()
 6155                .flatten()
 6156        })
 6157    }
 6158
 6159    pub fn confirm_code_action(
 6160        &mut self,
 6161        action: &ConfirmCodeAction,
 6162        window: &mut Window,
 6163        cx: &mut Context<Self>,
 6164    ) -> Option<Task<Result<()>>> {
 6165        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6166
 6167        let actions_menu =
 6168            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6169                menu
 6170            } else {
 6171                return None;
 6172            };
 6173
 6174        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6175        let action = actions_menu.actions.get(action_ix)?;
 6176        let title = action.label();
 6177        let buffer = actions_menu.buffer;
 6178        let workspace = self.workspace()?;
 6179
 6180        match action {
 6181            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6182                workspace.update(cx, |workspace, cx| {
 6183                    workspace.schedule_resolved_task(
 6184                        task_source_kind,
 6185                        resolved_task,
 6186                        false,
 6187                        window,
 6188                        cx,
 6189                    );
 6190
 6191                    Some(Task::ready(Ok(())))
 6192                })
 6193            }
 6194            CodeActionsItem::CodeAction {
 6195                excerpt_id,
 6196                action,
 6197                provider,
 6198            } => {
 6199                let apply_code_action =
 6200                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6201                let workspace = workspace.downgrade();
 6202                Some(cx.spawn_in(window, async move |editor, cx| {
 6203                    let project_transaction = apply_code_action.await?;
 6204                    Self::open_project_transaction(
 6205                        &editor,
 6206                        workspace,
 6207                        project_transaction,
 6208                        title,
 6209                        cx,
 6210                    )
 6211                    .await
 6212                }))
 6213            }
 6214            CodeActionsItem::DebugScenario(scenario) => {
 6215                let context = actions_menu.actions.context.clone();
 6216
 6217                workspace.update(cx, |workspace, cx| {
 6218                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6219                    workspace.start_debug_session(
 6220                        scenario,
 6221                        context,
 6222                        Some(buffer),
 6223                        None,
 6224                        window,
 6225                        cx,
 6226                    );
 6227                });
 6228                Some(Task::ready(Ok(())))
 6229            }
 6230        }
 6231    }
 6232
 6233    pub async fn open_project_transaction(
 6234        this: &WeakEntity<Editor>,
 6235        workspace: WeakEntity<Workspace>,
 6236        transaction: ProjectTransaction,
 6237        title: String,
 6238        cx: &mut AsyncWindowContext,
 6239    ) -> Result<()> {
 6240        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6241        cx.update(|_, cx| {
 6242            entries.sort_unstable_by_key(|(buffer, _)| {
 6243                buffer.read(cx).file().map(|f| f.path().clone())
 6244            });
 6245        })?;
 6246
 6247        // If the project transaction's edits are all contained within this editor, then
 6248        // avoid opening a new editor to display them.
 6249
 6250        if let Some((buffer, transaction)) = entries.first() {
 6251            if entries.len() == 1 {
 6252                let excerpt = this.update(cx, |editor, cx| {
 6253                    editor
 6254                        .buffer()
 6255                        .read(cx)
 6256                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6257                })?;
 6258                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6259                    if excerpted_buffer == *buffer {
 6260                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6261                            let excerpt_range = excerpt_range.to_offset(buffer);
 6262                            buffer
 6263                                .edited_ranges_for_transaction::<usize>(transaction)
 6264                                .all(|range| {
 6265                                    excerpt_range.start <= range.start
 6266                                        && excerpt_range.end >= range.end
 6267                                })
 6268                        })?;
 6269
 6270                        if all_edits_within_excerpt {
 6271                            return Ok(());
 6272                        }
 6273                    }
 6274                }
 6275            }
 6276        } else {
 6277            return Ok(());
 6278        }
 6279
 6280        let mut ranges_to_highlight = Vec::new();
 6281        let excerpt_buffer = cx.new(|cx| {
 6282            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6283            for (buffer_handle, transaction) in &entries {
 6284                let edited_ranges = buffer_handle
 6285                    .read(cx)
 6286                    .edited_ranges_for_transaction::<Point>(transaction)
 6287                    .collect::<Vec<_>>();
 6288                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6289                    PathKey::for_buffer(buffer_handle, cx),
 6290                    buffer_handle.clone(),
 6291                    edited_ranges,
 6292                    DEFAULT_MULTIBUFFER_CONTEXT,
 6293                    cx,
 6294                );
 6295
 6296                ranges_to_highlight.extend(ranges);
 6297            }
 6298            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6299            multibuffer
 6300        })?;
 6301
 6302        workspace.update_in(cx, |workspace, window, cx| {
 6303            let project = workspace.project().clone();
 6304            let editor =
 6305                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6306            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6307            editor.update(cx, |editor, cx| {
 6308                editor.highlight_background::<Self>(
 6309                    &ranges_to_highlight,
 6310                    |theme| theme.colors().editor_highlighted_line_background,
 6311                    cx,
 6312                );
 6313            });
 6314        })?;
 6315
 6316        Ok(())
 6317    }
 6318
 6319    pub fn clear_code_action_providers(&mut self) {
 6320        self.code_action_providers.clear();
 6321        self.available_code_actions.take();
 6322    }
 6323
 6324    pub fn add_code_action_provider(
 6325        &mut self,
 6326        provider: Rc<dyn CodeActionProvider>,
 6327        window: &mut Window,
 6328        cx: &mut Context<Self>,
 6329    ) {
 6330        if self
 6331            .code_action_providers
 6332            .iter()
 6333            .any(|existing_provider| existing_provider.id() == provider.id())
 6334        {
 6335            return;
 6336        }
 6337
 6338        self.code_action_providers.push(provider);
 6339        self.refresh_code_actions(window, cx);
 6340    }
 6341
 6342    pub fn remove_code_action_provider(
 6343        &mut self,
 6344        id: Arc<str>,
 6345        window: &mut Window,
 6346        cx: &mut Context<Self>,
 6347    ) {
 6348        self.code_action_providers
 6349            .retain(|provider| provider.id() != id);
 6350        self.refresh_code_actions(window, cx);
 6351    }
 6352
 6353    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6354        !self.code_action_providers.is_empty()
 6355            && EditorSettings::get_global(cx).toolbar.code_actions
 6356    }
 6357
 6358    pub fn has_available_code_actions(&self) -> bool {
 6359        self.available_code_actions
 6360            .as_ref()
 6361            .is_some_and(|(_, actions)| !actions.is_empty())
 6362    }
 6363
 6364    fn render_inline_code_actions(
 6365        &self,
 6366        icon_size: ui::IconSize,
 6367        display_row: DisplayRow,
 6368        is_active: bool,
 6369        cx: &mut Context<Self>,
 6370    ) -> AnyElement {
 6371        let show_tooltip = !self.context_menu_visible();
 6372        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6373            .icon_size(icon_size)
 6374            .shape(ui::IconButtonShape::Square)
 6375            .style(ButtonStyle::Transparent)
 6376            .icon_color(ui::Color::Hidden)
 6377            .toggle_state(is_active)
 6378            .when(show_tooltip, |this| {
 6379                this.tooltip({
 6380                    let focus_handle = self.focus_handle.clone();
 6381                    move |window, cx| {
 6382                        Tooltip::for_action_in(
 6383                            "Toggle Code Actions",
 6384                            &ToggleCodeActions {
 6385                                deployed_from: None,
 6386                                quick_launch: false,
 6387                            },
 6388                            &focus_handle,
 6389                            window,
 6390                            cx,
 6391                        )
 6392                    }
 6393                })
 6394            })
 6395            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6396                window.focus(&editor.focus_handle(cx));
 6397                editor.toggle_code_actions(
 6398                    &crate::actions::ToggleCodeActions {
 6399                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6400                            display_row,
 6401                        )),
 6402                        quick_launch: false,
 6403                    },
 6404                    window,
 6405                    cx,
 6406                );
 6407            }))
 6408            .into_any_element()
 6409    }
 6410
 6411    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6412        &self.context_menu
 6413    }
 6414
 6415    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6416        let newest_selection = self.selections.newest_anchor().clone();
 6417        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6418        let buffer = self.buffer.read(cx);
 6419        if newest_selection.head().diff_base_anchor.is_some() {
 6420            return None;
 6421        }
 6422        let (start_buffer, start) =
 6423            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6424        let (end_buffer, end) =
 6425            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6426        if start_buffer != end_buffer {
 6427            return None;
 6428        }
 6429
 6430        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6431            cx.background_executor()
 6432                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6433                .await;
 6434
 6435            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6436                let providers = this.code_action_providers.clone();
 6437                let tasks = this
 6438                    .code_action_providers
 6439                    .iter()
 6440                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6441                    .collect::<Vec<_>>();
 6442                (providers, tasks)
 6443            })?;
 6444
 6445            let mut actions = Vec::new();
 6446            for (provider, provider_actions) in
 6447                providers.into_iter().zip(future::join_all(tasks).await)
 6448            {
 6449                if let Some(provider_actions) = provider_actions.log_err() {
 6450                    actions.extend(provider_actions.into_iter().map(|action| {
 6451                        AvailableCodeAction {
 6452                            excerpt_id: newest_selection.start.excerpt_id,
 6453                            action,
 6454                            provider: provider.clone(),
 6455                        }
 6456                    }));
 6457                }
 6458            }
 6459
 6460            this.update(cx, |this, cx| {
 6461                this.available_code_actions = if actions.is_empty() {
 6462                    None
 6463                } else {
 6464                    Some((
 6465                        Location {
 6466                            buffer: start_buffer,
 6467                            range: start..end,
 6468                        },
 6469                        actions.into(),
 6470                    ))
 6471                };
 6472                cx.notify();
 6473            })
 6474        }));
 6475        None
 6476    }
 6477
 6478    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6479        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6480            self.show_git_blame_inline = false;
 6481
 6482            self.show_git_blame_inline_delay_task =
 6483                Some(cx.spawn_in(window, async move |this, cx| {
 6484                    cx.background_executor().timer(delay).await;
 6485
 6486                    this.update(cx, |this, cx| {
 6487                        this.show_git_blame_inline = true;
 6488                        cx.notify();
 6489                    })
 6490                    .log_err();
 6491                }));
 6492        }
 6493    }
 6494
 6495    fn show_blame_popover(
 6496        &mut self,
 6497        blame_entry: &BlameEntry,
 6498        position: gpui::Point<Pixels>,
 6499        cx: &mut Context<Self>,
 6500    ) {
 6501        if let Some(state) = &mut self.inline_blame_popover {
 6502            state.hide_task.take();
 6503        } else {
 6504            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6505            let blame_entry = blame_entry.clone();
 6506            let show_task = cx.spawn(async move |editor, cx| {
 6507                cx.background_executor()
 6508                    .timer(std::time::Duration::from_millis(delay))
 6509                    .await;
 6510                editor
 6511                    .update(cx, |editor, cx| {
 6512                        editor.inline_blame_popover_show_task.take();
 6513                        let Some(blame) = editor.blame.as_ref() else {
 6514                            return;
 6515                        };
 6516                        let blame = blame.read(cx);
 6517                        let details = blame.details_for_entry(&blame_entry);
 6518                        let markdown = cx.new(|cx| {
 6519                            Markdown::new(
 6520                                details
 6521                                    .as_ref()
 6522                                    .map(|message| message.message.clone())
 6523                                    .unwrap_or_default(),
 6524                                None,
 6525                                None,
 6526                                cx,
 6527                            )
 6528                        });
 6529                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6530                            position,
 6531                            hide_task: None,
 6532                            popover_bounds: None,
 6533                            popover_state: InlineBlamePopoverState {
 6534                                scroll_handle: ScrollHandle::new(),
 6535                                commit_message: details,
 6536                                markdown,
 6537                            },
 6538                        });
 6539                        cx.notify();
 6540                    })
 6541                    .ok();
 6542            });
 6543            self.inline_blame_popover_show_task = Some(show_task);
 6544        }
 6545    }
 6546
 6547    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6548        self.inline_blame_popover_show_task.take();
 6549        if let Some(state) = &mut self.inline_blame_popover {
 6550            let hide_task = cx.spawn(async move |editor, cx| {
 6551                cx.background_executor()
 6552                    .timer(std::time::Duration::from_millis(100))
 6553                    .await;
 6554                editor
 6555                    .update(cx, |editor, cx| {
 6556                        editor.inline_blame_popover.take();
 6557                        cx.notify();
 6558                    })
 6559                    .ok();
 6560            });
 6561            state.hide_task = Some(hide_task);
 6562        }
 6563    }
 6564
 6565    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6566        if self.pending_rename.is_some() {
 6567            return None;
 6568        }
 6569
 6570        let provider = self.semantics_provider.clone()?;
 6571        let buffer = self.buffer.read(cx);
 6572        let newest_selection = self.selections.newest_anchor().clone();
 6573        let cursor_position = newest_selection.head();
 6574        let (cursor_buffer, cursor_buffer_position) =
 6575            buffer.text_anchor_for_position(cursor_position, cx)?;
 6576        let (tail_buffer, tail_buffer_position) =
 6577            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6578        if cursor_buffer != tail_buffer {
 6579            return None;
 6580        }
 6581
 6582        let snapshot = cursor_buffer.read(cx).snapshot();
 6583        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6584        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6585        if start_word_range != end_word_range {
 6586            self.document_highlights_task.take();
 6587            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6588            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6589            return None;
 6590        }
 6591
 6592        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6593        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6594            cx.background_executor()
 6595                .timer(Duration::from_millis(debounce))
 6596                .await;
 6597
 6598            let highlights = if let Some(highlights) = cx
 6599                .update(|cx| {
 6600                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6601                })
 6602                .ok()
 6603                .flatten()
 6604            {
 6605                highlights.await.log_err()
 6606            } else {
 6607                None
 6608            };
 6609
 6610            if let Some(highlights) = highlights {
 6611                this.update(cx, |this, cx| {
 6612                    if this.pending_rename.is_some() {
 6613                        return;
 6614                    }
 6615
 6616                    let buffer_id = cursor_position.buffer_id;
 6617                    let buffer = this.buffer.read(cx);
 6618                    if !buffer
 6619                        .text_anchor_for_position(cursor_position, cx)
 6620                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6621                    {
 6622                        return;
 6623                    }
 6624
 6625                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6626                    let mut write_ranges = Vec::new();
 6627                    let mut read_ranges = Vec::new();
 6628                    for highlight in highlights {
 6629                        for (excerpt_id, excerpt_range) in
 6630                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6631                        {
 6632                            let start = highlight
 6633                                .range
 6634                                .start
 6635                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6636                            let end = highlight
 6637                                .range
 6638                                .end
 6639                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6640                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6641                                continue;
 6642                            }
 6643
 6644                            let range = Anchor {
 6645                                buffer_id,
 6646                                excerpt_id,
 6647                                text_anchor: start,
 6648                                diff_base_anchor: None,
 6649                            }..Anchor {
 6650                                buffer_id,
 6651                                excerpt_id,
 6652                                text_anchor: end,
 6653                                diff_base_anchor: None,
 6654                            };
 6655                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6656                                write_ranges.push(range);
 6657                            } else {
 6658                                read_ranges.push(range);
 6659                            }
 6660                        }
 6661                    }
 6662
 6663                    this.highlight_background::<DocumentHighlightRead>(
 6664                        &read_ranges,
 6665                        |theme| theme.colors().editor_document_highlight_read_background,
 6666                        cx,
 6667                    );
 6668                    this.highlight_background::<DocumentHighlightWrite>(
 6669                        &write_ranges,
 6670                        |theme| theme.colors().editor_document_highlight_write_background,
 6671                        cx,
 6672                    );
 6673                    cx.notify();
 6674                })
 6675                .log_err();
 6676            }
 6677        }));
 6678        None
 6679    }
 6680
 6681    fn prepare_highlight_query_from_selection(
 6682        &mut self,
 6683        cx: &mut Context<Editor>,
 6684    ) -> Option<(String, Range<Anchor>)> {
 6685        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6686            return None;
 6687        }
 6688        if !EditorSettings::get_global(cx).selection_highlight {
 6689            return None;
 6690        }
 6691        if self.selections.count() != 1 || self.selections.line_mode {
 6692            return None;
 6693        }
 6694        let selection = self.selections.newest::<Point>(cx);
 6695        if selection.is_empty() || selection.start.row != selection.end.row {
 6696            return None;
 6697        }
 6698        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6699        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6700        let query = multi_buffer_snapshot
 6701            .text_for_range(selection_anchor_range.clone())
 6702            .collect::<String>();
 6703        if query.trim().is_empty() {
 6704            return None;
 6705        }
 6706        Some((query, selection_anchor_range))
 6707    }
 6708
 6709    fn update_selection_occurrence_highlights(
 6710        &mut self,
 6711        query_text: String,
 6712        query_range: Range<Anchor>,
 6713        multi_buffer_range_to_query: Range<Point>,
 6714        use_debounce: bool,
 6715        window: &mut Window,
 6716        cx: &mut Context<Editor>,
 6717    ) -> Task<()> {
 6718        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6719        cx.spawn_in(window, async move |editor, cx| {
 6720            if use_debounce {
 6721                cx.background_executor()
 6722                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6723                    .await;
 6724            }
 6725            let match_task = cx.background_spawn(async move {
 6726                let buffer_ranges = multi_buffer_snapshot
 6727                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6728                    .into_iter()
 6729                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6730                let mut match_ranges = Vec::new();
 6731                let Ok(regex) = project::search::SearchQuery::text(
 6732                    query_text.clone(),
 6733                    false,
 6734                    false,
 6735                    false,
 6736                    Default::default(),
 6737                    Default::default(),
 6738                    false,
 6739                    None,
 6740                ) else {
 6741                    return Vec::default();
 6742                };
 6743                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6744                    match_ranges.extend(
 6745                        regex
 6746                            .search(&buffer_snapshot, Some(search_range.clone()))
 6747                            .await
 6748                            .into_iter()
 6749                            .filter_map(|match_range| {
 6750                                let match_start = buffer_snapshot
 6751                                    .anchor_after(search_range.start + match_range.start);
 6752                                let match_end = buffer_snapshot
 6753                                    .anchor_before(search_range.start + match_range.end);
 6754                                let match_anchor_range = Anchor::range_in_buffer(
 6755                                    excerpt_id,
 6756                                    buffer_snapshot.remote_id(),
 6757                                    match_start..match_end,
 6758                                );
 6759                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6760                            }),
 6761                    );
 6762                }
 6763                match_ranges
 6764            });
 6765            let match_ranges = match_task.await;
 6766            editor
 6767                .update_in(cx, |editor, _, cx| {
 6768                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6769                    if !match_ranges.is_empty() {
 6770                        editor.highlight_background::<SelectedTextHighlight>(
 6771                            &match_ranges,
 6772                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6773                            cx,
 6774                        )
 6775                    }
 6776                })
 6777                .log_err();
 6778        })
 6779    }
 6780
 6781    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6782        struct NewlineFold;
 6783        let type_id = std::any::TypeId::of::<NewlineFold>();
 6784        if !self.mode.is_single_line() {
 6785            return;
 6786        }
 6787        let snapshot = self.snapshot(window, cx);
 6788        if snapshot.buffer_snapshot.max_point().row == 0 {
 6789            return;
 6790        }
 6791        let task = cx.background_spawn(async move {
 6792            let new_newlines = snapshot
 6793                .buffer_chars_at(0)
 6794                .filter_map(|(c, i)| {
 6795                    if c == '\n' {
 6796                        Some(
 6797                            snapshot.buffer_snapshot.anchor_after(i)
 6798                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6799                        )
 6800                    } else {
 6801                        None
 6802                    }
 6803                })
 6804                .collect::<Vec<_>>();
 6805            let existing_newlines = snapshot
 6806                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6807                .filter_map(|fold| {
 6808                    if fold.placeholder.type_tag == Some(type_id) {
 6809                        Some(fold.range.start..fold.range.end)
 6810                    } else {
 6811                        None
 6812                    }
 6813                })
 6814                .collect::<Vec<_>>();
 6815
 6816            (new_newlines, existing_newlines)
 6817        });
 6818        self.folding_newlines = cx.spawn(async move |this, cx| {
 6819            let (new_newlines, existing_newlines) = task.await;
 6820            if new_newlines == existing_newlines {
 6821                return;
 6822            }
 6823            let placeholder = FoldPlaceholder {
 6824                render: Arc::new(move |_, _, cx| {
 6825                    div()
 6826                        .bg(cx.theme().status().hint_background)
 6827                        .border_b_1()
 6828                        .size_full()
 6829                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6830                        .border_color(cx.theme().status().hint)
 6831                        .child("\\n")
 6832                        .into_any()
 6833                }),
 6834                constrain_width: false,
 6835                merge_adjacent: false,
 6836                type_tag: Some(type_id),
 6837            };
 6838            let creases = new_newlines
 6839                .into_iter()
 6840                .map(|range| Crease::simple(range, placeholder.clone()))
 6841                .collect();
 6842            this.update(cx, |this, cx| {
 6843                this.display_map.update(cx, |display_map, cx| {
 6844                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6845                    display_map.fold(creases, cx);
 6846                });
 6847            })
 6848            .ok();
 6849        });
 6850    }
 6851
 6852    fn refresh_selected_text_highlights(
 6853        &mut self,
 6854        on_buffer_edit: bool,
 6855        window: &mut Window,
 6856        cx: &mut Context<Editor>,
 6857    ) {
 6858        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6859        else {
 6860            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6861            self.quick_selection_highlight_task.take();
 6862            self.debounced_selection_highlight_task.take();
 6863            return;
 6864        };
 6865        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6866        if on_buffer_edit
 6867            || self
 6868                .quick_selection_highlight_task
 6869                .as_ref()
 6870                .map_or(true, |(prev_anchor_range, _)| {
 6871                    prev_anchor_range != &query_range
 6872                })
 6873        {
 6874            let multi_buffer_visible_start = self
 6875                .scroll_manager
 6876                .anchor()
 6877                .anchor
 6878                .to_point(&multi_buffer_snapshot);
 6879            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6880                multi_buffer_visible_start
 6881                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6882                Bias::Left,
 6883            );
 6884            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6885            self.quick_selection_highlight_task = Some((
 6886                query_range.clone(),
 6887                self.update_selection_occurrence_highlights(
 6888                    query_text.clone(),
 6889                    query_range.clone(),
 6890                    multi_buffer_visible_range,
 6891                    false,
 6892                    window,
 6893                    cx,
 6894                ),
 6895            ));
 6896        }
 6897        if on_buffer_edit
 6898            || self
 6899                .debounced_selection_highlight_task
 6900                .as_ref()
 6901                .map_or(true, |(prev_anchor_range, _)| {
 6902                    prev_anchor_range != &query_range
 6903                })
 6904        {
 6905            let multi_buffer_start = multi_buffer_snapshot
 6906                .anchor_before(0)
 6907                .to_point(&multi_buffer_snapshot);
 6908            let multi_buffer_end = multi_buffer_snapshot
 6909                .anchor_after(multi_buffer_snapshot.len())
 6910                .to_point(&multi_buffer_snapshot);
 6911            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6912            self.debounced_selection_highlight_task = Some((
 6913                query_range.clone(),
 6914                self.update_selection_occurrence_highlights(
 6915                    query_text,
 6916                    query_range,
 6917                    multi_buffer_full_range,
 6918                    true,
 6919                    window,
 6920                    cx,
 6921                ),
 6922            ));
 6923        }
 6924    }
 6925
 6926    pub fn refresh_inline_completion(
 6927        &mut self,
 6928        debounce: bool,
 6929        user_requested: bool,
 6930        window: &mut Window,
 6931        cx: &mut Context<Self>,
 6932    ) -> Option<()> {
 6933        let provider = self.edit_prediction_provider()?;
 6934        let cursor = self.selections.newest_anchor().head();
 6935        let (buffer, cursor_buffer_position) =
 6936            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6937
 6938        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6939            self.discard_inline_completion(false, cx);
 6940            return None;
 6941        }
 6942
 6943        if !user_requested
 6944            && (!self.should_show_edit_predictions()
 6945                || !self.is_focused(window)
 6946                || buffer.read(cx).is_empty())
 6947        {
 6948            self.discard_inline_completion(false, cx);
 6949            return None;
 6950        }
 6951
 6952        self.update_visible_inline_completion(window, cx);
 6953        provider.refresh(
 6954            self.project.clone(),
 6955            buffer,
 6956            cursor_buffer_position,
 6957            debounce,
 6958            cx,
 6959        );
 6960        Some(())
 6961    }
 6962
 6963    fn show_edit_predictions_in_menu(&self) -> bool {
 6964        match self.edit_prediction_settings {
 6965            EditPredictionSettings::Disabled => false,
 6966            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6967        }
 6968    }
 6969
 6970    pub fn edit_predictions_enabled(&self) -> bool {
 6971        match self.edit_prediction_settings {
 6972            EditPredictionSettings::Disabled => false,
 6973            EditPredictionSettings::Enabled { .. } => true,
 6974        }
 6975    }
 6976
 6977    fn edit_prediction_requires_modifier(&self) -> bool {
 6978        match self.edit_prediction_settings {
 6979            EditPredictionSettings::Disabled => false,
 6980            EditPredictionSettings::Enabled {
 6981                preview_requires_modifier,
 6982                ..
 6983            } => preview_requires_modifier,
 6984        }
 6985    }
 6986
 6987    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6988        if self.edit_prediction_provider.is_none() {
 6989            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6990        } else {
 6991            let selection = self.selections.newest_anchor();
 6992            let cursor = selection.head();
 6993
 6994            if let Some((buffer, cursor_buffer_position)) =
 6995                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6996            {
 6997                self.edit_prediction_settings =
 6998                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6999            }
 7000        }
 7001    }
 7002
 7003    fn edit_prediction_settings_at_position(
 7004        &self,
 7005        buffer: &Entity<Buffer>,
 7006        buffer_position: language::Anchor,
 7007        cx: &App,
 7008    ) -> EditPredictionSettings {
 7009        if !self.mode.is_full()
 7010            || !self.show_inline_completions_override.unwrap_or(true)
 7011            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7012        {
 7013            return EditPredictionSettings::Disabled;
 7014        }
 7015
 7016        let buffer = buffer.read(cx);
 7017
 7018        let file = buffer.file();
 7019
 7020        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7021            return EditPredictionSettings::Disabled;
 7022        };
 7023
 7024        let by_provider = matches!(
 7025            self.menu_inline_completions_policy,
 7026            MenuInlineCompletionsPolicy::ByProvider
 7027        );
 7028
 7029        let show_in_menu = by_provider
 7030            && self
 7031                .edit_prediction_provider
 7032                .as_ref()
 7033                .map_or(false, |provider| {
 7034                    provider.provider.show_completions_in_menu()
 7035                });
 7036
 7037        let preview_requires_modifier =
 7038            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7039
 7040        EditPredictionSettings::Enabled {
 7041            show_in_menu,
 7042            preview_requires_modifier,
 7043        }
 7044    }
 7045
 7046    fn should_show_edit_predictions(&self) -> bool {
 7047        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7048    }
 7049
 7050    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7051        matches!(
 7052            self.edit_prediction_preview,
 7053            EditPredictionPreview::Active { .. }
 7054        )
 7055    }
 7056
 7057    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7058        let cursor = self.selections.newest_anchor().head();
 7059        if let Some((buffer, cursor_position)) =
 7060            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7061        {
 7062            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7063        } else {
 7064            false
 7065        }
 7066    }
 7067
 7068    pub fn supports_minimap(&self, cx: &App) -> bool {
 7069        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7070    }
 7071
 7072    fn edit_predictions_enabled_in_buffer(
 7073        &self,
 7074        buffer: &Entity<Buffer>,
 7075        buffer_position: language::Anchor,
 7076        cx: &App,
 7077    ) -> bool {
 7078        maybe!({
 7079            if self.read_only(cx) {
 7080                return Some(false);
 7081            }
 7082            let provider = self.edit_prediction_provider()?;
 7083            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7084                return Some(false);
 7085            }
 7086            let buffer = buffer.read(cx);
 7087            let Some(file) = buffer.file() else {
 7088                return Some(true);
 7089            };
 7090            let settings = all_language_settings(Some(file), cx);
 7091            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7092        })
 7093        .unwrap_or(false)
 7094    }
 7095
 7096    fn cycle_inline_completion(
 7097        &mut self,
 7098        direction: Direction,
 7099        window: &mut Window,
 7100        cx: &mut Context<Self>,
 7101    ) -> Option<()> {
 7102        let provider = self.edit_prediction_provider()?;
 7103        let cursor = self.selections.newest_anchor().head();
 7104        let (buffer, cursor_buffer_position) =
 7105            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7106        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7107            return None;
 7108        }
 7109
 7110        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7111        self.update_visible_inline_completion(window, cx);
 7112
 7113        Some(())
 7114    }
 7115
 7116    pub fn show_inline_completion(
 7117        &mut self,
 7118        _: &ShowEditPrediction,
 7119        window: &mut Window,
 7120        cx: &mut Context<Self>,
 7121    ) {
 7122        if !self.has_active_inline_completion() {
 7123            self.refresh_inline_completion(false, true, window, cx);
 7124            return;
 7125        }
 7126
 7127        self.update_visible_inline_completion(window, cx);
 7128    }
 7129
 7130    pub fn display_cursor_names(
 7131        &mut self,
 7132        _: &DisplayCursorNames,
 7133        window: &mut Window,
 7134        cx: &mut Context<Self>,
 7135    ) {
 7136        self.show_cursor_names(window, cx);
 7137    }
 7138
 7139    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7140        self.show_cursor_names = true;
 7141        cx.notify();
 7142        cx.spawn_in(window, async move |this, cx| {
 7143            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7144            this.update(cx, |this, cx| {
 7145                this.show_cursor_names = false;
 7146                cx.notify()
 7147            })
 7148            .ok()
 7149        })
 7150        .detach();
 7151    }
 7152
 7153    pub fn next_edit_prediction(
 7154        &mut self,
 7155        _: &NextEditPrediction,
 7156        window: &mut Window,
 7157        cx: &mut Context<Self>,
 7158    ) {
 7159        if self.has_active_inline_completion() {
 7160            self.cycle_inline_completion(Direction::Next, window, cx);
 7161        } else {
 7162            let is_copilot_disabled = self
 7163                .refresh_inline_completion(false, true, window, cx)
 7164                .is_none();
 7165            if is_copilot_disabled {
 7166                cx.propagate();
 7167            }
 7168        }
 7169    }
 7170
 7171    pub fn previous_edit_prediction(
 7172        &mut self,
 7173        _: &PreviousEditPrediction,
 7174        window: &mut Window,
 7175        cx: &mut Context<Self>,
 7176    ) {
 7177        if self.has_active_inline_completion() {
 7178            self.cycle_inline_completion(Direction::Prev, window, cx);
 7179        } else {
 7180            let is_copilot_disabled = self
 7181                .refresh_inline_completion(false, true, window, cx)
 7182                .is_none();
 7183            if is_copilot_disabled {
 7184                cx.propagate();
 7185            }
 7186        }
 7187    }
 7188
 7189    pub fn accept_edit_prediction(
 7190        &mut self,
 7191        _: &AcceptEditPrediction,
 7192        window: &mut Window,
 7193        cx: &mut Context<Self>,
 7194    ) {
 7195        if self.show_edit_predictions_in_menu() {
 7196            self.hide_context_menu(window, cx);
 7197        }
 7198
 7199        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7200            return;
 7201        };
 7202
 7203        self.report_inline_completion_event(
 7204            active_inline_completion.completion_id.clone(),
 7205            true,
 7206            cx,
 7207        );
 7208
 7209        match &active_inline_completion.completion {
 7210            InlineCompletion::Move { target, .. } => {
 7211                let target = *target;
 7212
 7213                if let Some(position_map) = &self.last_position_map {
 7214                    if position_map
 7215                        .visible_row_range
 7216                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7217                        || !self.edit_prediction_requires_modifier()
 7218                    {
 7219                        self.unfold_ranges(&[target..target], true, false, cx);
 7220                        // Note that this is also done in vim's handler of the Tab action.
 7221                        self.change_selections(
 7222                            SelectionEffects::scroll(Autoscroll::newest()),
 7223                            window,
 7224                            cx,
 7225                            |selections| {
 7226                                selections.select_anchor_ranges([target..target]);
 7227                            },
 7228                        );
 7229                        self.clear_row_highlights::<EditPredictionPreview>();
 7230
 7231                        self.edit_prediction_preview
 7232                            .set_previous_scroll_position(None);
 7233                    } else {
 7234                        self.edit_prediction_preview
 7235                            .set_previous_scroll_position(Some(
 7236                                position_map.snapshot.scroll_anchor,
 7237                            ));
 7238
 7239                        self.highlight_rows::<EditPredictionPreview>(
 7240                            target..target,
 7241                            cx.theme().colors().editor_highlighted_line_background,
 7242                            RowHighlightOptions {
 7243                                autoscroll: true,
 7244                                ..Default::default()
 7245                            },
 7246                            cx,
 7247                        );
 7248                        self.request_autoscroll(Autoscroll::fit(), cx);
 7249                    }
 7250                }
 7251            }
 7252            InlineCompletion::Edit { edits, .. } => {
 7253                if let Some(provider) = self.edit_prediction_provider() {
 7254                    provider.accept(cx);
 7255                }
 7256
 7257                // Store the transaction ID and selections before applying the edit
 7258                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7259
 7260                let snapshot = self.buffer.read(cx).snapshot(cx);
 7261                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7262
 7263                self.buffer.update(cx, |buffer, cx| {
 7264                    buffer.edit(edits.iter().cloned(), None, cx)
 7265                });
 7266
 7267                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7268                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7269                });
 7270
 7271                let selections = self.selections.disjoint_anchors();
 7272                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7273                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7274                    if has_new_transaction {
 7275                        self.selection_history
 7276                            .insert_transaction(transaction_id_now, selections);
 7277                    }
 7278                }
 7279
 7280                self.update_visible_inline_completion(window, cx);
 7281                if self.active_inline_completion.is_none() {
 7282                    self.refresh_inline_completion(true, true, window, cx);
 7283                }
 7284
 7285                cx.notify();
 7286            }
 7287        }
 7288
 7289        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7290    }
 7291
 7292    pub fn accept_partial_inline_completion(
 7293        &mut self,
 7294        _: &AcceptPartialEditPrediction,
 7295        window: &mut Window,
 7296        cx: &mut Context<Self>,
 7297    ) {
 7298        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7299            return;
 7300        };
 7301        if self.selections.count() != 1 {
 7302            return;
 7303        }
 7304
 7305        self.report_inline_completion_event(
 7306            active_inline_completion.completion_id.clone(),
 7307            true,
 7308            cx,
 7309        );
 7310
 7311        match &active_inline_completion.completion {
 7312            InlineCompletion::Move { target, .. } => {
 7313                let target = *target;
 7314                self.change_selections(
 7315                    SelectionEffects::scroll(Autoscroll::newest()),
 7316                    window,
 7317                    cx,
 7318                    |selections| {
 7319                        selections.select_anchor_ranges([target..target]);
 7320                    },
 7321                );
 7322            }
 7323            InlineCompletion::Edit { edits, .. } => {
 7324                // Find an insertion that starts at the cursor position.
 7325                let snapshot = self.buffer.read(cx).snapshot(cx);
 7326                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7327                let insertion = edits.iter().find_map(|(range, text)| {
 7328                    let range = range.to_offset(&snapshot);
 7329                    if range.is_empty() && range.start == cursor_offset {
 7330                        Some(text)
 7331                    } else {
 7332                        None
 7333                    }
 7334                });
 7335
 7336                if let Some(text) = insertion {
 7337                    let mut partial_completion = text
 7338                        .chars()
 7339                        .by_ref()
 7340                        .take_while(|c| c.is_alphabetic())
 7341                        .collect::<String>();
 7342                    if partial_completion.is_empty() {
 7343                        partial_completion = text
 7344                            .chars()
 7345                            .by_ref()
 7346                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7347                            .collect::<String>();
 7348                    }
 7349
 7350                    cx.emit(EditorEvent::InputHandled {
 7351                        utf16_range_to_replace: None,
 7352                        text: partial_completion.clone().into(),
 7353                    });
 7354
 7355                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7356
 7357                    self.refresh_inline_completion(true, true, window, cx);
 7358                    cx.notify();
 7359                } else {
 7360                    self.accept_edit_prediction(&Default::default(), window, cx);
 7361                }
 7362            }
 7363        }
 7364    }
 7365
 7366    fn discard_inline_completion(
 7367        &mut self,
 7368        should_report_inline_completion_event: bool,
 7369        cx: &mut Context<Self>,
 7370    ) -> bool {
 7371        if should_report_inline_completion_event {
 7372            let completion_id = self
 7373                .active_inline_completion
 7374                .as_ref()
 7375                .and_then(|active_completion| active_completion.completion_id.clone());
 7376
 7377            self.report_inline_completion_event(completion_id, false, cx);
 7378        }
 7379
 7380        if let Some(provider) = self.edit_prediction_provider() {
 7381            provider.discard(cx);
 7382        }
 7383
 7384        self.take_active_inline_completion(cx)
 7385    }
 7386
 7387    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7388        let Some(provider) = self.edit_prediction_provider() else {
 7389            return;
 7390        };
 7391
 7392        let Some((_, buffer, _)) = self
 7393            .buffer
 7394            .read(cx)
 7395            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7396        else {
 7397            return;
 7398        };
 7399
 7400        let extension = buffer
 7401            .read(cx)
 7402            .file()
 7403            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7404
 7405        let event_type = match accepted {
 7406            true => "Edit Prediction Accepted",
 7407            false => "Edit Prediction Discarded",
 7408        };
 7409        telemetry::event!(
 7410            event_type,
 7411            provider = provider.name(),
 7412            prediction_id = id,
 7413            suggestion_accepted = accepted,
 7414            file_extension = extension,
 7415        );
 7416    }
 7417
 7418    pub fn has_active_inline_completion(&self) -> bool {
 7419        self.active_inline_completion.is_some()
 7420    }
 7421
 7422    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7423        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7424            return false;
 7425        };
 7426
 7427        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7428        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7429        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7430        true
 7431    }
 7432
 7433    /// Returns true when we're displaying the edit prediction popover below the cursor
 7434    /// like we are not previewing and the LSP autocomplete menu is visible
 7435    /// or we are in `when_holding_modifier` mode.
 7436    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7437        if self.edit_prediction_preview_is_active()
 7438            || !self.show_edit_predictions_in_menu()
 7439            || !self.edit_predictions_enabled()
 7440        {
 7441            return false;
 7442        }
 7443
 7444        if self.has_visible_completions_menu() {
 7445            return true;
 7446        }
 7447
 7448        has_completion && self.edit_prediction_requires_modifier()
 7449    }
 7450
 7451    fn handle_modifiers_changed(
 7452        &mut self,
 7453        modifiers: Modifiers,
 7454        position_map: &PositionMap,
 7455        window: &mut Window,
 7456        cx: &mut Context<Self>,
 7457    ) {
 7458        if self.show_edit_predictions_in_menu() {
 7459            self.update_edit_prediction_preview(&modifiers, window, cx);
 7460        }
 7461
 7462        self.update_selection_mode(&modifiers, position_map, window, cx);
 7463
 7464        let mouse_position = window.mouse_position();
 7465        if !position_map.text_hitbox.is_hovered(window) {
 7466            return;
 7467        }
 7468
 7469        self.update_hovered_link(
 7470            position_map.point_for_position(mouse_position),
 7471            &position_map.snapshot,
 7472            modifiers,
 7473            window,
 7474            cx,
 7475        )
 7476    }
 7477
 7478    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7479        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7480        if invert {
 7481            match multi_cursor_setting {
 7482                MultiCursorModifier::Alt => modifiers.alt,
 7483                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7484            }
 7485        } else {
 7486            match multi_cursor_setting {
 7487                MultiCursorModifier::Alt => modifiers.secondary(),
 7488                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7489            }
 7490        }
 7491    }
 7492
 7493    fn columnar_selection_mode(
 7494        modifiers: &Modifiers,
 7495        cx: &mut Context<Self>,
 7496    ) -> Option<ColumnarMode> {
 7497        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7498            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7499                Some(ColumnarMode::FromMouse)
 7500            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7501                Some(ColumnarMode::FromSelection)
 7502            } else {
 7503                None
 7504            }
 7505        } else {
 7506            None
 7507        }
 7508    }
 7509
 7510    fn update_selection_mode(
 7511        &mut self,
 7512        modifiers: &Modifiers,
 7513        position_map: &PositionMap,
 7514        window: &mut Window,
 7515        cx: &mut Context<Self>,
 7516    ) {
 7517        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7518            return;
 7519        };
 7520        if self.selections.pending.is_none() {
 7521            return;
 7522        }
 7523
 7524        let mouse_position = window.mouse_position();
 7525        let point_for_position = position_map.point_for_position(mouse_position);
 7526        let position = point_for_position.previous_valid;
 7527
 7528        self.select(
 7529            SelectPhase::BeginColumnar {
 7530                position,
 7531                reset: false,
 7532                mode,
 7533                goal_column: point_for_position.exact_unclipped.column(),
 7534            },
 7535            window,
 7536            cx,
 7537        );
 7538    }
 7539
 7540    fn update_edit_prediction_preview(
 7541        &mut self,
 7542        modifiers: &Modifiers,
 7543        window: &mut Window,
 7544        cx: &mut Context<Self>,
 7545    ) {
 7546        let mut modifiers_held = false;
 7547        if let Some(accept_keystroke) = self
 7548            .accept_edit_prediction_keybind(false, window, cx)
 7549            .keystroke()
 7550        {
 7551            modifiers_held = modifiers_held
 7552                || (&accept_keystroke.modifiers == modifiers
 7553                    && accept_keystroke.modifiers.modified());
 7554        };
 7555        if let Some(accept_partial_keystroke) = self
 7556            .accept_edit_prediction_keybind(true, window, cx)
 7557            .keystroke()
 7558        {
 7559            modifiers_held = modifiers_held
 7560                || (&accept_partial_keystroke.modifiers == modifiers
 7561                    && accept_partial_keystroke.modifiers.modified());
 7562        }
 7563
 7564        if modifiers_held {
 7565            if matches!(
 7566                self.edit_prediction_preview,
 7567                EditPredictionPreview::Inactive { .. }
 7568            ) {
 7569                self.edit_prediction_preview = EditPredictionPreview::Active {
 7570                    previous_scroll_position: None,
 7571                    since: Instant::now(),
 7572                };
 7573
 7574                self.update_visible_inline_completion(window, cx);
 7575                cx.notify();
 7576            }
 7577        } else if let EditPredictionPreview::Active {
 7578            previous_scroll_position,
 7579            since,
 7580        } = self.edit_prediction_preview
 7581        {
 7582            if let (Some(previous_scroll_position), Some(position_map)) =
 7583                (previous_scroll_position, self.last_position_map.as_ref())
 7584            {
 7585                self.set_scroll_position(
 7586                    previous_scroll_position
 7587                        .scroll_position(&position_map.snapshot.display_snapshot),
 7588                    window,
 7589                    cx,
 7590                );
 7591            }
 7592
 7593            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7594                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7595            };
 7596            self.clear_row_highlights::<EditPredictionPreview>();
 7597            self.update_visible_inline_completion(window, cx);
 7598            cx.notify();
 7599        }
 7600    }
 7601
 7602    fn update_visible_inline_completion(
 7603        &mut self,
 7604        _window: &mut Window,
 7605        cx: &mut Context<Self>,
 7606    ) -> Option<()> {
 7607        let selection = self.selections.newest_anchor();
 7608        let cursor = selection.head();
 7609        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7610        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7611        let excerpt_id = cursor.excerpt_id;
 7612
 7613        let show_in_menu = self.show_edit_predictions_in_menu();
 7614        let completions_menu_has_precedence = !show_in_menu
 7615            && (self.context_menu.borrow().is_some()
 7616                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7617
 7618        if completions_menu_has_precedence
 7619            || !offset_selection.is_empty()
 7620            || self
 7621                .active_inline_completion
 7622                .as_ref()
 7623                .map_or(false, |completion| {
 7624                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7625                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7626                    !invalidation_range.contains(&offset_selection.head())
 7627                })
 7628        {
 7629            self.discard_inline_completion(false, cx);
 7630            return None;
 7631        }
 7632
 7633        self.take_active_inline_completion(cx);
 7634        let Some(provider) = self.edit_prediction_provider() else {
 7635            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7636            return None;
 7637        };
 7638
 7639        let (buffer, cursor_buffer_position) =
 7640            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7641
 7642        self.edit_prediction_settings =
 7643            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7644
 7645        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7646
 7647        if self.edit_prediction_indent_conflict {
 7648            let cursor_point = cursor.to_point(&multibuffer);
 7649
 7650            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7651
 7652            if let Some((_, indent)) = indents.iter().next() {
 7653                if indent.len == cursor_point.column {
 7654                    self.edit_prediction_indent_conflict = false;
 7655                }
 7656            }
 7657        }
 7658
 7659        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7660        let edits = inline_completion
 7661            .edits
 7662            .into_iter()
 7663            .flat_map(|(range, new_text)| {
 7664                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7665                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7666                Some((start..end, new_text))
 7667            })
 7668            .collect::<Vec<_>>();
 7669        if edits.is_empty() {
 7670            return None;
 7671        }
 7672
 7673        let first_edit_start = edits.first().unwrap().0.start;
 7674        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7675        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7676
 7677        let last_edit_end = edits.last().unwrap().0.end;
 7678        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7679        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7680
 7681        let cursor_row = cursor.to_point(&multibuffer).row;
 7682
 7683        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7684
 7685        let mut inlay_ids = Vec::new();
 7686        let invalidation_row_range;
 7687        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7688            Some(cursor_row..edit_end_row)
 7689        } else if cursor_row > edit_end_row {
 7690            Some(edit_start_row..cursor_row)
 7691        } else {
 7692            None
 7693        };
 7694        let is_move =
 7695            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7696        let completion = if is_move {
 7697            invalidation_row_range =
 7698                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7699            let target = first_edit_start;
 7700            InlineCompletion::Move { target, snapshot }
 7701        } else {
 7702            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7703                && !self.inline_completions_hidden_for_vim_mode;
 7704
 7705            if show_completions_in_buffer {
 7706                if edits
 7707                    .iter()
 7708                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7709                {
 7710                    let mut inlays = Vec::new();
 7711                    for (range, new_text) in &edits {
 7712                        let inlay = Inlay::inline_completion(
 7713                            post_inc(&mut self.next_inlay_id),
 7714                            range.start,
 7715                            new_text.as_str(),
 7716                        );
 7717                        inlay_ids.push(inlay.id);
 7718                        inlays.push(inlay);
 7719                    }
 7720
 7721                    self.splice_inlays(&[], inlays, cx);
 7722                } else {
 7723                    let background_color = cx.theme().status().deleted_background;
 7724                    self.highlight_text::<InlineCompletionHighlight>(
 7725                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7726                        HighlightStyle {
 7727                            background_color: Some(background_color),
 7728                            ..Default::default()
 7729                        },
 7730                        cx,
 7731                    );
 7732                }
 7733            }
 7734
 7735            invalidation_row_range = edit_start_row..edit_end_row;
 7736
 7737            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7738                if provider.show_tab_accept_marker() {
 7739                    EditDisplayMode::TabAccept
 7740                } else {
 7741                    EditDisplayMode::Inline
 7742                }
 7743            } else {
 7744                EditDisplayMode::DiffPopover
 7745            };
 7746
 7747            InlineCompletion::Edit {
 7748                edits,
 7749                edit_preview: inline_completion.edit_preview,
 7750                display_mode,
 7751                snapshot,
 7752            }
 7753        };
 7754
 7755        let invalidation_range = multibuffer
 7756            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7757            ..multibuffer.anchor_after(Point::new(
 7758                invalidation_row_range.end,
 7759                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7760            ));
 7761
 7762        self.stale_inline_completion_in_menu = None;
 7763        self.active_inline_completion = Some(InlineCompletionState {
 7764            inlay_ids,
 7765            completion,
 7766            completion_id: inline_completion.id,
 7767            invalidation_range,
 7768        });
 7769
 7770        cx.notify();
 7771
 7772        Some(())
 7773    }
 7774
 7775    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7776        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7777    }
 7778
 7779    fn clear_tasks(&mut self) {
 7780        self.tasks.clear()
 7781    }
 7782
 7783    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7784        if self.tasks.insert(key, value).is_some() {
 7785            // This case should hopefully be rare, but just in case...
 7786            log::error!(
 7787                "multiple different run targets found on a single line, only the last target will be rendered"
 7788            )
 7789        }
 7790    }
 7791
 7792    /// Get all display points of breakpoints that will be rendered within editor
 7793    ///
 7794    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7795    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7796    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7797    fn active_breakpoints(
 7798        &self,
 7799        range: Range<DisplayRow>,
 7800        window: &mut Window,
 7801        cx: &mut Context<Self>,
 7802    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7803        let mut breakpoint_display_points = HashMap::default();
 7804
 7805        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7806            return breakpoint_display_points;
 7807        };
 7808
 7809        let snapshot = self.snapshot(window, cx);
 7810
 7811        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7812        let Some(project) = self.project.as_ref() else {
 7813            return breakpoint_display_points;
 7814        };
 7815
 7816        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7817            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7818
 7819        for (buffer_snapshot, range, excerpt_id) in
 7820            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7821        {
 7822            let Some(buffer) = project
 7823                .read(cx)
 7824                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7825            else {
 7826                continue;
 7827            };
 7828            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7829                &buffer,
 7830                Some(
 7831                    buffer_snapshot.anchor_before(range.start)
 7832                        ..buffer_snapshot.anchor_after(range.end),
 7833                ),
 7834                buffer_snapshot,
 7835                cx,
 7836            );
 7837            for (breakpoint, state) in breakpoints {
 7838                let multi_buffer_anchor =
 7839                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7840                let position = multi_buffer_anchor
 7841                    .to_point(&multi_buffer_snapshot)
 7842                    .to_display_point(&snapshot);
 7843
 7844                breakpoint_display_points.insert(
 7845                    position.row(),
 7846                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7847                );
 7848            }
 7849        }
 7850
 7851        breakpoint_display_points
 7852    }
 7853
 7854    fn breakpoint_context_menu(
 7855        &self,
 7856        anchor: Anchor,
 7857        window: &mut Window,
 7858        cx: &mut Context<Self>,
 7859    ) -> Entity<ui::ContextMenu> {
 7860        let weak_editor = cx.weak_entity();
 7861        let focus_handle = self.focus_handle(cx);
 7862
 7863        let row = self
 7864            .buffer
 7865            .read(cx)
 7866            .snapshot(cx)
 7867            .summary_for_anchor::<Point>(&anchor)
 7868            .row;
 7869
 7870        let breakpoint = self
 7871            .breakpoint_at_row(row, window, cx)
 7872            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7873
 7874        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7875            "Edit Log Breakpoint"
 7876        } else {
 7877            "Set Log Breakpoint"
 7878        };
 7879
 7880        let condition_breakpoint_msg = if breakpoint
 7881            .as_ref()
 7882            .is_some_and(|bp| bp.1.condition.is_some())
 7883        {
 7884            "Edit Condition Breakpoint"
 7885        } else {
 7886            "Set Condition Breakpoint"
 7887        };
 7888
 7889        let hit_condition_breakpoint_msg = if breakpoint
 7890            .as_ref()
 7891            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7892        {
 7893            "Edit Hit Condition Breakpoint"
 7894        } else {
 7895            "Set Hit Condition Breakpoint"
 7896        };
 7897
 7898        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7899            "Unset Breakpoint"
 7900        } else {
 7901            "Set Breakpoint"
 7902        };
 7903
 7904        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7905
 7906        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7907            BreakpointState::Enabled => Some("Disable"),
 7908            BreakpointState::Disabled => Some("Enable"),
 7909        });
 7910
 7911        let (anchor, breakpoint) =
 7912            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7913
 7914        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7915            menu.on_blur_subscription(Subscription::new(|| {}))
 7916                .context(focus_handle)
 7917                .when(run_to_cursor, |this| {
 7918                    let weak_editor = weak_editor.clone();
 7919                    this.entry("Run to cursor", None, move |window, cx| {
 7920                        weak_editor
 7921                            .update(cx, |editor, cx| {
 7922                                editor.change_selections(
 7923                                    SelectionEffects::no_scroll(),
 7924                                    window,
 7925                                    cx,
 7926                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7927                                );
 7928                            })
 7929                            .ok();
 7930
 7931                        window.dispatch_action(Box::new(RunToCursor), cx);
 7932                    })
 7933                    .separator()
 7934                })
 7935                .when_some(toggle_state_msg, |this, msg| {
 7936                    this.entry(msg, None, {
 7937                        let weak_editor = weak_editor.clone();
 7938                        let breakpoint = breakpoint.clone();
 7939                        move |_window, cx| {
 7940                            weak_editor
 7941                                .update(cx, |this, cx| {
 7942                                    this.edit_breakpoint_at_anchor(
 7943                                        anchor,
 7944                                        breakpoint.as_ref().clone(),
 7945                                        BreakpointEditAction::InvertState,
 7946                                        cx,
 7947                                    );
 7948                                })
 7949                                .log_err();
 7950                        }
 7951                    })
 7952                })
 7953                .entry(set_breakpoint_msg, None, {
 7954                    let weak_editor = weak_editor.clone();
 7955                    let breakpoint = breakpoint.clone();
 7956                    move |_window, cx| {
 7957                        weak_editor
 7958                            .update(cx, |this, cx| {
 7959                                this.edit_breakpoint_at_anchor(
 7960                                    anchor,
 7961                                    breakpoint.as_ref().clone(),
 7962                                    BreakpointEditAction::Toggle,
 7963                                    cx,
 7964                                );
 7965                            })
 7966                            .log_err();
 7967                    }
 7968                })
 7969                .entry(log_breakpoint_msg, None, {
 7970                    let breakpoint = breakpoint.clone();
 7971                    let weak_editor = weak_editor.clone();
 7972                    move |window, cx| {
 7973                        weak_editor
 7974                            .update(cx, |this, cx| {
 7975                                this.add_edit_breakpoint_block(
 7976                                    anchor,
 7977                                    breakpoint.as_ref(),
 7978                                    BreakpointPromptEditAction::Log,
 7979                                    window,
 7980                                    cx,
 7981                                );
 7982                            })
 7983                            .log_err();
 7984                    }
 7985                })
 7986                .entry(condition_breakpoint_msg, None, {
 7987                    let breakpoint = breakpoint.clone();
 7988                    let weak_editor = weak_editor.clone();
 7989                    move |window, cx| {
 7990                        weak_editor
 7991                            .update(cx, |this, cx| {
 7992                                this.add_edit_breakpoint_block(
 7993                                    anchor,
 7994                                    breakpoint.as_ref(),
 7995                                    BreakpointPromptEditAction::Condition,
 7996                                    window,
 7997                                    cx,
 7998                                );
 7999                            })
 8000                            .log_err();
 8001                    }
 8002                })
 8003                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8004                    weak_editor
 8005                        .update(cx, |this, cx| {
 8006                            this.add_edit_breakpoint_block(
 8007                                anchor,
 8008                                breakpoint.as_ref(),
 8009                                BreakpointPromptEditAction::HitCondition,
 8010                                window,
 8011                                cx,
 8012                            );
 8013                        })
 8014                        .log_err();
 8015                })
 8016        })
 8017    }
 8018
 8019    fn render_breakpoint(
 8020        &self,
 8021        position: Anchor,
 8022        row: DisplayRow,
 8023        breakpoint: &Breakpoint,
 8024        state: Option<BreakpointSessionState>,
 8025        cx: &mut Context<Self>,
 8026    ) -> IconButton {
 8027        let is_rejected = state.is_some_and(|s| !s.verified);
 8028        // Is it a breakpoint that shows up when hovering over gutter?
 8029        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8030            (false, false),
 8031            |PhantomBreakpointIndicator {
 8032                 is_active,
 8033                 display_row,
 8034                 collides_with_existing_breakpoint,
 8035             }| {
 8036                (
 8037                    is_active && display_row == row,
 8038                    collides_with_existing_breakpoint,
 8039                )
 8040            },
 8041        );
 8042
 8043        let (color, icon) = {
 8044            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8045                (false, false) => ui::IconName::DebugBreakpoint,
 8046                (true, false) => ui::IconName::DebugLogBreakpoint,
 8047                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8048                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8049            };
 8050
 8051            let color = if is_phantom {
 8052                Color::Hint
 8053            } else if is_rejected {
 8054                Color::Disabled
 8055            } else {
 8056                Color::Debugger
 8057            };
 8058
 8059            (color, icon)
 8060        };
 8061
 8062        let breakpoint = Arc::from(breakpoint.clone());
 8063
 8064        let alt_as_text = gpui::Keystroke {
 8065            modifiers: Modifiers::secondary_key(),
 8066            ..Default::default()
 8067        };
 8068        let primary_action_text = if breakpoint.is_disabled() {
 8069            "Enable breakpoint"
 8070        } else if is_phantom && !collides_with_existing {
 8071            "Set breakpoint"
 8072        } else {
 8073            "Unset breakpoint"
 8074        };
 8075        let focus_handle = self.focus_handle.clone();
 8076
 8077        let meta = if is_rejected {
 8078            SharedString::from("No executable code is associated with this line.")
 8079        } else if collides_with_existing && !breakpoint.is_disabled() {
 8080            SharedString::from(format!(
 8081                "{alt_as_text}-click to disable,\nright-click for more options."
 8082            ))
 8083        } else {
 8084            SharedString::from("Right-click for more options.")
 8085        };
 8086        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8087            .icon_size(IconSize::XSmall)
 8088            .size(ui::ButtonSize::None)
 8089            .when(is_rejected, |this| {
 8090                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8091            })
 8092            .icon_color(color)
 8093            .style(ButtonStyle::Transparent)
 8094            .on_click(cx.listener({
 8095                let breakpoint = breakpoint.clone();
 8096
 8097                move |editor, event: &ClickEvent, window, cx| {
 8098                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8099                        BreakpointEditAction::InvertState
 8100                    } else {
 8101                        BreakpointEditAction::Toggle
 8102                    };
 8103
 8104                    window.focus(&editor.focus_handle(cx));
 8105                    editor.edit_breakpoint_at_anchor(
 8106                        position,
 8107                        breakpoint.as_ref().clone(),
 8108                        edit_action,
 8109                        cx,
 8110                    );
 8111                }
 8112            }))
 8113            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8114                editor.set_breakpoint_context_menu(
 8115                    row,
 8116                    Some(position),
 8117                    event.down.position,
 8118                    window,
 8119                    cx,
 8120                );
 8121            }))
 8122            .tooltip(move |window, cx| {
 8123                Tooltip::with_meta_in(
 8124                    primary_action_text,
 8125                    Some(&ToggleBreakpoint),
 8126                    meta.clone(),
 8127                    &focus_handle,
 8128                    window,
 8129                    cx,
 8130                )
 8131            })
 8132    }
 8133
 8134    fn build_tasks_context(
 8135        project: &Entity<Project>,
 8136        buffer: &Entity<Buffer>,
 8137        buffer_row: u32,
 8138        tasks: &Arc<RunnableTasks>,
 8139        cx: &mut Context<Self>,
 8140    ) -> Task<Option<task::TaskContext>> {
 8141        let position = Point::new(buffer_row, tasks.column);
 8142        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8143        let location = Location {
 8144            buffer: buffer.clone(),
 8145            range: range_start..range_start,
 8146        };
 8147        // Fill in the environmental variables from the tree-sitter captures
 8148        let mut captured_task_variables = TaskVariables::default();
 8149        for (capture_name, value) in tasks.extra_variables.clone() {
 8150            captured_task_variables.insert(
 8151                task::VariableName::Custom(capture_name.into()),
 8152                value.clone(),
 8153            );
 8154        }
 8155        project.update(cx, |project, cx| {
 8156            project.task_store().update(cx, |task_store, cx| {
 8157                task_store.task_context_for_location(captured_task_variables, location, cx)
 8158            })
 8159        })
 8160    }
 8161
 8162    pub fn spawn_nearest_task(
 8163        &mut self,
 8164        action: &SpawnNearestTask,
 8165        window: &mut Window,
 8166        cx: &mut Context<Self>,
 8167    ) {
 8168        let Some((workspace, _)) = self.workspace.clone() else {
 8169            return;
 8170        };
 8171        let Some(project) = self.project.clone() else {
 8172            return;
 8173        };
 8174
 8175        // Try to find a closest, enclosing node using tree-sitter that has a
 8176        // task
 8177        let Some((buffer, buffer_row, tasks)) = self
 8178            .find_enclosing_node_task(cx)
 8179            // Or find the task that's closest in row-distance.
 8180            .or_else(|| self.find_closest_task(cx))
 8181        else {
 8182            return;
 8183        };
 8184
 8185        let reveal_strategy = action.reveal;
 8186        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8187        cx.spawn_in(window, async move |_, cx| {
 8188            let context = task_context.await?;
 8189            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8190
 8191            let resolved = &mut resolved_task.resolved;
 8192            resolved.reveal = reveal_strategy;
 8193
 8194            workspace
 8195                .update_in(cx, |workspace, window, cx| {
 8196                    workspace.schedule_resolved_task(
 8197                        task_source_kind,
 8198                        resolved_task,
 8199                        false,
 8200                        window,
 8201                        cx,
 8202                    );
 8203                })
 8204                .ok()
 8205        })
 8206        .detach();
 8207    }
 8208
 8209    fn find_closest_task(
 8210        &mut self,
 8211        cx: &mut Context<Self>,
 8212    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8213        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8214
 8215        let ((buffer_id, row), tasks) = self
 8216            .tasks
 8217            .iter()
 8218            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8219
 8220        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8221        let tasks = Arc::new(tasks.to_owned());
 8222        Some((buffer, *row, tasks))
 8223    }
 8224
 8225    fn find_enclosing_node_task(
 8226        &mut self,
 8227        cx: &mut Context<Self>,
 8228    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8229        let snapshot = self.buffer.read(cx).snapshot(cx);
 8230        let offset = self.selections.newest::<usize>(cx).head();
 8231        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8232        let buffer_id = excerpt.buffer().remote_id();
 8233
 8234        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8235        let mut cursor = layer.node().walk();
 8236
 8237        while cursor.goto_first_child_for_byte(offset).is_some() {
 8238            if cursor.node().end_byte() == offset {
 8239                cursor.goto_next_sibling();
 8240            }
 8241        }
 8242
 8243        // Ascend to the smallest ancestor that contains the range and has a task.
 8244        loop {
 8245            let node = cursor.node();
 8246            let node_range = node.byte_range();
 8247            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8248
 8249            // Check if this node contains our offset
 8250            if node_range.start <= offset && node_range.end >= offset {
 8251                // If it contains offset, check for task
 8252                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8253                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8254                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8255                }
 8256            }
 8257
 8258            if !cursor.goto_parent() {
 8259                break;
 8260            }
 8261        }
 8262        None
 8263    }
 8264
 8265    fn render_run_indicator(
 8266        &self,
 8267        _style: &EditorStyle,
 8268        is_active: bool,
 8269        row: DisplayRow,
 8270        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8271        cx: &mut Context<Self>,
 8272    ) -> IconButton {
 8273        let color = Color::Muted;
 8274        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8275
 8276        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8277            .shape(ui::IconButtonShape::Square)
 8278            .icon_size(IconSize::XSmall)
 8279            .icon_color(color)
 8280            .toggle_state(is_active)
 8281            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8282                let quick_launch = e.down.button == MouseButton::Left;
 8283                window.focus(&editor.focus_handle(cx));
 8284                editor.toggle_code_actions(
 8285                    &ToggleCodeActions {
 8286                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8287                        quick_launch,
 8288                    },
 8289                    window,
 8290                    cx,
 8291                );
 8292            }))
 8293            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8294                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8295            }))
 8296    }
 8297
 8298    pub fn context_menu_visible(&self) -> bool {
 8299        !self.edit_prediction_preview_is_active()
 8300            && self
 8301                .context_menu
 8302                .borrow()
 8303                .as_ref()
 8304                .map_or(false, |menu| menu.visible())
 8305    }
 8306
 8307    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8308        self.context_menu
 8309            .borrow()
 8310            .as_ref()
 8311            .map(|menu| menu.origin())
 8312    }
 8313
 8314    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8315        self.context_menu_options = Some(options);
 8316    }
 8317
 8318    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8319    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8320
 8321    fn render_edit_prediction_popover(
 8322        &mut self,
 8323        text_bounds: &Bounds<Pixels>,
 8324        content_origin: gpui::Point<Pixels>,
 8325        right_margin: Pixels,
 8326        editor_snapshot: &EditorSnapshot,
 8327        visible_row_range: Range<DisplayRow>,
 8328        scroll_top: f32,
 8329        scroll_bottom: f32,
 8330        line_layouts: &[LineWithInvisibles],
 8331        line_height: Pixels,
 8332        scroll_pixel_position: gpui::Point<Pixels>,
 8333        newest_selection_head: Option<DisplayPoint>,
 8334        editor_width: Pixels,
 8335        style: &EditorStyle,
 8336        window: &mut Window,
 8337        cx: &mut App,
 8338    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8339        if self.mode().is_minimap() {
 8340            return None;
 8341        }
 8342        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8343
 8344        if self.edit_prediction_visible_in_cursor_popover(true) {
 8345            return None;
 8346        }
 8347
 8348        match &active_inline_completion.completion {
 8349            InlineCompletion::Move { target, .. } => {
 8350                let target_display_point = target.to_display_point(editor_snapshot);
 8351
 8352                if self.edit_prediction_requires_modifier() {
 8353                    if !self.edit_prediction_preview_is_active() {
 8354                        return None;
 8355                    }
 8356
 8357                    self.render_edit_prediction_modifier_jump_popover(
 8358                        text_bounds,
 8359                        content_origin,
 8360                        visible_row_range,
 8361                        line_layouts,
 8362                        line_height,
 8363                        scroll_pixel_position,
 8364                        newest_selection_head,
 8365                        target_display_point,
 8366                        window,
 8367                        cx,
 8368                    )
 8369                } else {
 8370                    self.render_edit_prediction_eager_jump_popover(
 8371                        text_bounds,
 8372                        content_origin,
 8373                        editor_snapshot,
 8374                        visible_row_range,
 8375                        scroll_top,
 8376                        scroll_bottom,
 8377                        line_height,
 8378                        scroll_pixel_position,
 8379                        target_display_point,
 8380                        editor_width,
 8381                        window,
 8382                        cx,
 8383                    )
 8384                }
 8385            }
 8386            InlineCompletion::Edit {
 8387                display_mode: EditDisplayMode::Inline,
 8388                ..
 8389            } => None,
 8390            InlineCompletion::Edit {
 8391                display_mode: EditDisplayMode::TabAccept,
 8392                edits,
 8393                ..
 8394            } => {
 8395                let range = &edits.first()?.0;
 8396                let target_display_point = range.end.to_display_point(editor_snapshot);
 8397
 8398                self.render_edit_prediction_end_of_line_popover(
 8399                    "Accept",
 8400                    editor_snapshot,
 8401                    visible_row_range,
 8402                    target_display_point,
 8403                    line_height,
 8404                    scroll_pixel_position,
 8405                    content_origin,
 8406                    editor_width,
 8407                    window,
 8408                    cx,
 8409                )
 8410            }
 8411            InlineCompletion::Edit {
 8412                edits,
 8413                edit_preview,
 8414                display_mode: EditDisplayMode::DiffPopover,
 8415                snapshot,
 8416            } => self.render_edit_prediction_diff_popover(
 8417                text_bounds,
 8418                content_origin,
 8419                right_margin,
 8420                editor_snapshot,
 8421                visible_row_range,
 8422                line_layouts,
 8423                line_height,
 8424                scroll_pixel_position,
 8425                newest_selection_head,
 8426                editor_width,
 8427                style,
 8428                edits,
 8429                edit_preview,
 8430                snapshot,
 8431                window,
 8432                cx,
 8433            ),
 8434        }
 8435    }
 8436
 8437    fn render_edit_prediction_modifier_jump_popover(
 8438        &mut self,
 8439        text_bounds: &Bounds<Pixels>,
 8440        content_origin: gpui::Point<Pixels>,
 8441        visible_row_range: Range<DisplayRow>,
 8442        line_layouts: &[LineWithInvisibles],
 8443        line_height: Pixels,
 8444        scroll_pixel_position: gpui::Point<Pixels>,
 8445        newest_selection_head: Option<DisplayPoint>,
 8446        target_display_point: DisplayPoint,
 8447        window: &mut Window,
 8448        cx: &mut App,
 8449    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8450        let scrolled_content_origin =
 8451            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8452
 8453        const SCROLL_PADDING_Y: Pixels = px(12.);
 8454
 8455        if target_display_point.row() < visible_row_range.start {
 8456            return self.render_edit_prediction_scroll_popover(
 8457                |_| SCROLL_PADDING_Y,
 8458                IconName::ArrowUp,
 8459                visible_row_range,
 8460                line_layouts,
 8461                newest_selection_head,
 8462                scrolled_content_origin,
 8463                window,
 8464                cx,
 8465            );
 8466        } else if target_display_point.row() >= visible_row_range.end {
 8467            return self.render_edit_prediction_scroll_popover(
 8468                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8469                IconName::ArrowDown,
 8470                visible_row_range,
 8471                line_layouts,
 8472                newest_selection_head,
 8473                scrolled_content_origin,
 8474                window,
 8475                cx,
 8476            );
 8477        }
 8478
 8479        const POLE_WIDTH: Pixels = px(2.);
 8480
 8481        let line_layout =
 8482            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8483        let target_column = target_display_point.column() as usize;
 8484
 8485        let target_x = line_layout.x_for_index(target_column);
 8486        let target_y =
 8487            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8488
 8489        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8490
 8491        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8492        border_color.l += 0.001;
 8493
 8494        let mut element = v_flex()
 8495            .items_end()
 8496            .when(flag_on_right, |el| el.items_start())
 8497            .child(if flag_on_right {
 8498                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8499                    .rounded_bl(px(0.))
 8500                    .rounded_tl(px(0.))
 8501                    .border_l_2()
 8502                    .border_color(border_color)
 8503            } else {
 8504                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8505                    .rounded_br(px(0.))
 8506                    .rounded_tr(px(0.))
 8507                    .border_r_2()
 8508                    .border_color(border_color)
 8509            })
 8510            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8511            .into_any();
 8512
 8513        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8514
 8515        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8516            - point(
 8517                if flag_on_right {
 8518                    POLE_WIDTH
 8519                } else {
 8520                    size.width - POLE_WIDTH
 8521                },
 8522                size.height - line_height,
 8523            );
 8524
 8525        origin.x = origin.x.max(content_origin.x);
 8526
 8527        element.prepaint_at(origin, window, cx);
 8528
 8529        Some((element, origin))
 8530    }
 8531
 8532    fn render_edit_prediction_scroll_popover(
 8533        &mut self,
 8534        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8535        scroll_icon: IconName,
 8536        visible_row_range: Range<DisplayRow>,
 8537        line_layouts: &[LineWithInvisibles],
 8538        newest_selection_head: Option<DisplayPoint>,
 8539        scrolled_content_origin: gpui::Point<Pixels>,
 8540        window: &mut Window,
 8541        cx: &mut App,
 8542    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8543        let mut element = self
 8544            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8545            .into_any();
 8546
 8547        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8548
 8549        let cursor = newest_selection_head?;
 8550        let cursor_row_layout =
 8551            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8552        let cursor_column = cursor.column() as usize;
 8553
 8554        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8555
 8556        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8557
 8558        element.prepaint_at(origin, window, cx);
 8559        Some((element, origin))
 8560    }
 8561
 8562    fn render_edit_prediction_eager_jump_popover(
 8563        &mut self,
 8564        text_bounds: &Bounds<Pixels>,
 8565        content_origin: gpui::Point<Pixels>,
 8566        editor_snapshot: &EditorSnapshot,
 8567        visible_row_range: Range<DisplayRow>,
 8568        scroll_top: f32,
 8569        scroll_bottom: f32,
 8570        line_height: Pixels,
 8571        scroll_pixel_position: gpui::Point<Pixels>,
 8572        target_display_point: DisplayPoint,
 8573        editor_width: Pixels,
 8574        window: &mut Window,
 8575        cx: &mut App,
 8576    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8577        if target_display_point.row().as_f32() < scroll_top {
 8578            let mut element = self
 8579                .render_edit_prediction_line_popover(
 8580                    "Jump to Edit",
 8581                    Some(IconName::ArrowUp),
 8582                    window,
 8583                    cx,
 8584                )?
 8585                .into_any();
 8586
 8587            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8588            let offset = point(
 8589                (text_bounds.size.width - size.width) / 2.,
 8590                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8591            );
 8592
 8593            let origin = text_bounds.origin + offset;
 8594            element.prepaint_at(origin, window, cx);
 8595            Some((element, origin))
 8596        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8597            let mut element = self
 8598                .render_edit_prediction_line_popover(
 8599                    "Jump to Edit",
 8600                    Some(IconName::ArrowDown),
 8601                    window,
 8602                    cx,
 8603                )?
 8604                .into_any();
 8605
 8606            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8607            let offset = point(
 8608                (text_bounds.size.width - size.width) / 2.,
 8609                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8610            );
 8611
 8612            let origin = text_bounds.origin + offset;
 8613            element.prepaint_at(origin, window, cx);
 8614            Some((element, origin))
 8615        } else {
 8616            self.render_edit_prediction_end_of_line_popover(
 8617                "Jump to Edit",
 8618                editor_snapshot,
 8619                visible_row_range,
 8620                target_display_point,
 8621                line_height,
 8622                scroll_pixel_position,
 8623                content_origin,
 8624                editor_width,
 8625                window,
 8626                cx,
 8627            )
 8628        }
 8629    }
 8630
 8631    fn render_edit_prediction_end_of_line_popover(
 8632        self: &mut Editor,
 8633        label: &'static str,
 8634        editor_snapshot: &EditorSnapshot,
 8635        visible_row_range: Range<DisplayRow>,
 8636        target_display_point: DisplayPoint,
 8637        line_height: Pixels,
 8638        scroll_pixel_position: gpui::Point<Pixels>,
 8639        content_origin: gpui::Point<Pixels>,
 8640        editor_width: Pixels,
 8641        window: &mut Window,
 8642        cx: &mut App,
 8643    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8644        let target_line_end = DisplayPoint::new(
 8645            target_display_point.row(),
 8646            editor_snapshot.line_len(target_display_point.row()),
 8647        );
 8648
 8649        let mut element = self
 8650            .render_edit_prediction_line_popover(label, None, window, cx)?
 8651            .into_any();
 8652
 8653        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8654
 8655        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8656
 8657        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8658        let mut origin = start_point
 8659            + line_origin
 8660            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8661        origin.x = origin.x.max(content_origin.x);
 8662
 8663        let max_x = content_origin.x + editor_width - size.width;
 8664
 8665        if origin.x > max_x {
 8666            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8667
 8668            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8669                origin.y += offset;
 8670                IconName::ArrowUp
 8671            } else {
 8672                origin.y -= offset;
 8673                IconName::ArrowDown
 8674            };
 8675
 8676            element = self
 8677                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8678                .into_any();
 8679
 8680            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8681
 8682            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8683        }
 8684
 8685        element.prepaint_at(origin, window, cx);
 8686        Some((element, origin))
 8687    }
 8688
 8689    fn render_edit_prediction_diff_popover(
 8690        self: &Editor,
 8691        text_bounds: &Bounds<Pixels>,
 8692        content_origin: gpui::Point<Pixels>,
 8693        right_margin: Pixels,
 8694        editor_snapshot: &EditorSnapshot,
 8695        visible_row_range: Range<DisplayRow>,
 8696        line_layouts: &[LineWithInvisibles],
 8697        line_height: Pixels,
 8698        scroll_pixel_position: gpui::Point<Pixels>,
 8699        newest_selection_head: Option<DisplayPoint>,
 8700        editor_width: Pixels,
 8701        style: &EditorStyle,
 8702        edits: &Vec<(Range<Anchor>, String)>,
 8703        edit_preview: &Option<language::EditPreview>,
 8704        snapshot: &language::BufferSnapshot,
 8705        window: &mut Window,
 8706        cx: &mut App,
 8707    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8708        let edit_start = edits
 8709            .first()
 8710            .unwrap()
 8711            .0
 8712            .start
 8713            .to_display_point(editor_snapshot);
 8714        let edit_end = edits
 8715            .last()
 8716            .unwrap()
 8717            .0
 8718            .end
 8719            .to_display_point(editor_snapshot);
 8720
 8721        let is_visible = visible_row_range.contains(&edit_start.row())
 8722            || visible_row_range.contains(&edit_end.row());
 8723        if !is_visible {
 8724            return None;
 8725        }
 8726
 8727        let highlighted_edits =
 8728            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8729
 8730        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8731        let line_count = highlighted_edits.text.lines().count();
 8732
 8733        const BORDER_WIDTH: Pixels = px(1.);
 8734
 8735        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8736        let has_keybind = keybind.is_some();
 8737
 8738        let mut element = h_flex()
 8739            .items_start()
 8740            .child(
 8741                h_flex()
 8742                    .bg(cx.theme().colors().editor_background)
 8743                    .border(BORDER_WIDTH)
 8744                    .shadow_xs()
 8745                    .border_color(cx.theme().colors().border)
 8746                    .rounded_l_lg()
 8747                    .when(line_count > 1, |el| el.rounded_br_lg())
 8748                    .pr_1()
 8749                    .child(styled_text),
 8750            )
 8751            .child(
 8752                h_flex()
 8753                    .h(line_height + BORDER_WIDTH * 2.)
 8754                    .px_1p5()
 8755                    .gap_1()
 8756                    // Workaround: For some reason, there's a gap if we don't do this
 8757                    .ml(-BORDER_WIDTH)
 8758                    .shadow(vec![gpui::BoxShadow {
 8759                        color: gpui::black().opacity(0.05),
 8760                        offset: point(px(1.), px(1.)),
 8761                        blur_radius: px(2.),
 8762                        spread_radius: px(0.),
 8763                    }])
 8764                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8765                    .border(BORDER_WIDTH)
 8766                    .border_color(cx.theme().colors().border)
 8767                    .rounded_r_lg()
 8768                    .id("edit_prediction_diff_popover_keybind")
 8769                    .when(!has_keybind, |el| {
 8770                        let status_colors = cx.theme().status();
 8771
 8772                        el.bg(status_colors.error_background)
 8773                            .border_color(status_colors.error.opacity(0.6))
 8774                            .child(Icon::new(IconName::Info).color(Color::Error))
 8775                            .cursor_default()
 8776                            .hoverable_tooltip(move |_window, cx| {
 8777                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8778                            })
 8779                    })
 8780                    .children(keybind),
 8781            )
 8782            .into_any();
 8783
 8784        let longest_row =
 8785            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8786        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8787            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8788        } else {
 8789            layout_line(
 8790                longest_row,
 8791                editor_snapshot,
 8792                style,
 8793                editor_width,
 8794                |_| false,
 8795                window,
 8796                cx,
 8797            )
 8798            .width
 8799        };
 8800
 8801        let viewport_bounds =
 8802            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8803                right: -right_margin,
 8804                ..Default::default()
 8805            });
 8806
 8807        let x_after_longest =
 8808            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8809                - scroll_pixel_position.x;
 8810
 8811        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8812
 8813        // Fully visible if it can be displayed within the window (allow overlapping other
 8814        // panes). However, this is only allowed if the popover starts within text_bounds.
 8815        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8816            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8817
 8818        let mut origin = if can_position_to_the_right {
 8819            point(
 8820                x_after_longest,
 8821                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8822                    - scroll_pixel_position.y,
 8823            )
 8824        } else {
 8825            let cursor_row = newest_selection_head.map(|head| head.row());
 8826            let above_edit = edit_start
 8827                .row()
 8828                .0
 8829                .checked_sub(line_count as u32)
 8830                .map(DisplayRow);
 8831            let below_edit = Some(edit_end.row() + 1);
 8832            let above_cursor =
 8833                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8834            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8835
 8836            // Place the edit popover adjacent to the edit if there is a location
 8837            // available that is onscreen and does not obscure the cursor. Otherwise,
 8838            // place it adjacent to the cursor.
 8839            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8840                .into_iter()
 8841                .flatten()
 8842                .find(|&start_row| {
 8843                    let end_row = start_row + line_count as u32;
 8844                    visible_row_range.contains(&start_row)
 8845                        && visible_row_range.contains(&end_row)
 8846                        && cursor_row.map_or(true, |cursor_row| {
 8847                            !((start_row..end_row).contains(&cursor_row))
 8848                        })
 8849                })?;
 8850
 8851            content_origin
 8852                + point(
 8853                    -scroll_pixel_position.x,
 8854                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8855                )
 8856        };
 8857
 8858        origin.x -= BORDER_WIDTH;
 8859
 8860        window.defer_draw(element, origin, 1);
 8861
 8862        // Do not return an element, since it will already be drawn due to defer_draw.
 8863        None
 8864    }
 8865
 8866    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8867        px(30.)
 8868    }
 8869
 8870    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8871        if self.read_only(cx) {
 8872            cx.theme().players().read_only()
 8873        } else {
 8874            self.style.as_ref().unwrap().local_player
 8875        }
 8876    }
 8877
 8878    fn render_edit_prediction_accept_keybind(
 8879        &self,
 8880        window: &mut Window,
 8881        cx: &App,
 8882    ) -> Option<AnyElement> {
 8883        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8884        let accept_keystroke = accept_binding.keystroke()?;
 8885
 8886        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8887
 8888        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8889            Color::Accent
 8890        } else {
 8891            Color::Muted
 8892        };
 8893
 8894        h_flex()
 8895            .px_0p5()
 8896            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8897            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8898            .text_size(TextSize::XSmall.rems(cx))
 8899            .child(h_flex().children(ui::render_modifiers(
 8900                &accept_keystroke.modifiers,
 8901                PlatformStyle::platform(),
 8902                Some(modifiers_color),
 8903                Some(IconSize::XSmall.rems().into()),
 8904                true,
 8905            )))
 8906            .when(is_platform_style_mac, |parent| {
 8907                parent.child(accept_keystroke.key.clone())
 8908            })
 8909            .when(!is_platform_style_mac, |parent| {
 8910                parent.child(
 8911                    Key::new(
 8912                        util::capitalize(&accept_keystroke.key),
 8913                        Some(Color::Default),
 8914                    )
 8915                    .size(Some(IconSize::XSmall.rems().into())),
 8916                )
 8917            })
 8918            .into_any()
 8919            .into()
 8920    }
 8921
 8922    fn render_edit_prediction_line_popover(
 8923        &self,
 8924        label: impl Into<SharedString>,
 8925        icon: Option<IconName>,
 8926        window: &mut Window,
 8927        cx: &App,
 8928    ) -> Option<Stateful<Div>> {
 8929        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8930
 8931        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8932        let has_keybind = keybind.is_some();
 8933
 8934        let result = h_flex()
 8935            .id("ep-line-popover")
 8936            .py_0p5()
 8937            .pl_1()
 8938            .pr(padding_right)
 8939            .gap_1()
 8940            .rounded_md()
 8941            .border_1()
 8942            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8943            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8944            .shadow_xs()
 8945            .when(!has_keybind, |el| {
 8946                let status_colors = cx.theme().status();
 8947
 8948                el.bg(status_colors.error_background)
 8949                    .border_color(status_colors.error.opacity(0.6))
 8950                    .pl_2()
 8951                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8952                    .cursor_default()
 8953                    .hoverable_tooltip(move |_window, cx| {
 8954                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8955                    })
 8956            })
 8957            .children(keybind)
 8958            .child(
 8959                Label::new(label)
 8960                    .size(LabelSize::Small)
 8961                    .when(!has_keybind, |el| {
 8962                        el.color(cx.theme().status().error.into()).strikethrough()
 8963                    }),
 8964            )
 8965            .when(!has_keybind, |el| {
 8966                el.child(
 8967                    h_flex().ml_1().child(
 8968                        Icon::new(IconName::Info)
 8969                            .size(IconSize::Small)
 8970                            .color(cx.theme().status().error.into()),
 8971                    ),
 8972                )
 8973            })
 8974            .when_some(icon, |element, icon| {
 8975                element.child(
 8976                    div()
 8977                        .mt(px(1.5))
 8978                        .child(Icon::new(icon).size(IconSize::Small)),
 8979                )
 8980            });
 8981
 8982        Some(result)
 8983    }
 8984
 8985    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8986        let accent_color = cx.theme().colors().text_accent;
 8987        let editor_bg_color = cx.theme().colors().editor_background;
 8988        editor_bg_color.blend(accent_color.opacity(0.1))
 8989    }
 8990
 8991    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8992        let accent_color = cx.theme().colors().text_accent;
 8993        let editor_bg_color = cx.theme().colors().editor_background;
 8994        editor_bg_color.blend(accent_color.opacity(0.6))
 8995    }
 8996
 8997    fn render_edit_prediction_cursor_popover(
 8998        &self,
 8999        min_width: Pixels,
 9000        max_width: Pixels,
 9001        cursor_point: Point,
 9002        style: &EditorStyle,
 9003        accept_keystroke: Option<&gpui::Keystroke>,
 9004        _window: &Window,
 9005        cx: &mut Context<Editor>,
 9006    ) -> Option<AnyElement> {
 9007        let provider = self.edit_prediction_provider.as_ref()?;
 9008
 9009        if provider.provider.needs_terms_acceptance(cx) {
 9010            return Some(
 9011                h_flex()
 9012                    .min_w(min_width)
 9013                    .flex_1()
 9014                    .px_2()
 9015                    .py_1()
 9016                    .gap_3()
 9017                    .elevation_2(cx)
 9018                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9019                    .id("accept-terms")
 9020                    .cursor_pointer()
 9021                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9022                    .on_click(cx.listener(|this, _event, window, cx| {
 9023                        cx.stop_propagation();
 9024                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9025                        window.dispatch_action(
 9026                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9027                            cx,
 9028                        );
 9029                    }))
 9030                    .child(
 9031                        h_flex()
 9032                            .flex_1()
 9033                            .gap_2()
 9034                            .child(Icon::new(IconName::ZedPredict))
 9035                            .child(Label::new("Accept Terms of Service"))
 9036                            .child(div().w_full())
 9037                            .child(
 9038                                Icon::new(IconName::ArrowUpRight)
 9039                                    .color(Color::Muted)
 9040                                    .size(IconSize::Small),
 9041                            )
 9042                            .into_any_element(),
 9043                    )
 9044                    .into_any(),
 9045            );
 9046        }
 9047
 9048        let is_refreshing = provider.provider.is_refreshing(cx);
 9049
 9050        fn pending_completion_container() -> Div {
 9051            h_flex()
 9052                .h_full()
 9053                .flex_1()
 9054                .gap_2()
 9055                .child(Icon::new(IconName::ZedPredict))
 9056        }
 9057
 9058        let completion = match &self.active_inline_completion {
 9059            Some(prediction) => {
 9060                if !self.has_visible_completions_menu() {
 9061                    const RADIUS: Pixels = px(6.);
 9062                    const BORDER_WIDTH: Pixels = px(1.);
 9063
 9064                    return Some(
 9065                        h_flex()
 9066                            .elevation_2(cx)
 9067                            .border(BORDER_WIDTH)
 9068                            .border_color(cx.theme().colors().border)
 9069                            .when(accept_keystroke.is_none(), |el| {
 9070                                el.border_color(cx.theme().status().error)
 9071                            })
 9072                            .rounded(RADIUS)
 9073                            .rounded_tl(px(0.))
 9074                            .overflow_hidden()
 9075                            .child(div().px_1p5().child(match &prediction.completion {
 9076                                InlineCompletion::Move { target, snapshot } => {
 9077                                    use text::ToPoint as _;
 9078                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9079                                    {
 9080                                        Icon::new(IconName::ZedPredictDown)
 9081                                    } else {
 9082                                        Icon::new(IconName::ZedPredictUp)
 9083                                    }
 9084                                }
 9085                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9086                            }))
 9087                            .child(
 9088                                h_flex()
 9089                                    .gap_1()
 9090                                    .py_1()
 9091                                    .px_2()
 9092                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9093                                    .border_l_1()
 9094                                    .border_color(cx.theme().colors().border)
 9095                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9096                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9097                                        el.child(
 9098                                            Label::new("Hold")
 9099                                                .size(LabelSize::Small)
 9100                                                .when(accept_keystroke.is_none(), |el| {
 9101                                                    el.strikethrough()
 9102                                                })
 9103                                                .line_height_style(LineHeightStyle::UiLabel),
 9104                                        )
 9105                                    })
 9106                                    .id("edit_prediction_cursor_popover_keybind")
 9107                                    .when(accept_keystroke.is_none(), |el| {
 9108                                        let status_colors = cx.theme().status();
 9109
 9110                                        el.bg(status_colors.error_background)
 9111                                            .border_color(status_colors.error.opacity(0.6))
 9112                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9113                                            .cursor_default()
 9114                                            .hoverable_tooltip(move |_window, cx| {
 9115                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9116                                                    .into()
 9117                                            })
 9118                                    })
 9119                                    .when_some(
 9120                                        accept_keystroke.as_ref(),
 9121                                        |el, accept_keystroke| {
 9122                                            el.child(h_flex().children(ui::render_modifiers(
 9123                                                &accept_keystroke.modifiers,
 9124                                                PlatformStyle::platform(),
 9125                                                Some(Color::Default),
 9126                                                Some(IconSize::XSmall.rems().into()),
 9127                                                false,
 9128                                            )))
 9129                                        },
 9130                                    ),
 9131                            )
 9132                            .into_any(),
 9133                    );
 9134                }
 9135
 9136                self.render_edit_prediction_cursor_popover_preview(
 9137                    prediction,
 9138                    cursor_point,
 9139                    style,
 9140                    cx,
 9141                )?
 9142            }
 9143
 9144            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9145                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9146                    stale_completion,
 9147                    cursor_point,
 9148                    style,
 9149                    cx,
 9150                )?,
 9151
 9152                None => {
 9153                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9154                }
 9155            },
 9156
 9157            None => pending_completion_container().child(Label::new("No Prediction")),
 9158        };
 9159
 9160        let completion = if is_refreshing {
 9161            completion
 9162                .with_animation(
 9163                    "loading-completion",
 9164                    Animation::new(Duration::from_secs(2))
 9165                        .repeat()
 9166                        .with_easing(pulsating_between(0.4, 0.8)),
 9167                    |label, delta| label.opacity(delta),
 9168                )
 9169                .into_any_element()
 9170        } else {
 9171            completion.into_any_element()
 9172        };
 9173
 9174        let has_completion = self.active_inline_completion.is_some();
 9175
 9176        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9177        Some(
 9178            h_flex()
 9179                .min_w(min_width)
 9180                .max_w(max_width)
 9181                .flex_1()
 9182                .elevation_2(cx)
 9183                .border_color(cx.theme().colors().border)
 9184                .child(
 9185                    div()
 9186                        .flex_1()
 9187                        .py_1()
 9188                        .px_2()
 9189                        .overflow_hidden()
 9190                        .child(completion),
 9191                )
 9192                .when_some(accept_keystroke, |el, accept_keystroke| {
 9193                    if !accept_keystroke.modifiers.modified() {
 9194                        return el;
 9195                    }
 9196
 9197                    el.child(
 9198                        h_flex()
 9199                            .h_full()
 9200                            .border_l_1()
 9201                            .rounded_r_lg()
 9202                            .border_color(cx.theme().colors().border)
 9203                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9204                            .gap_1()
 9205                            .py_1()
 9206                            .px_2()
 9207                            .child(
 9208                                h_flex()
 9209                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9210                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9211                                    .child(h_flex().children(ui::render_modifiers(
 9212                                        &accept_keystroke.modifiers,
 9213                                        PlatformStyle::platform(),
 9214                                        Some(if !has_completion {
 9215                                            Color::Muted
 9216                                        } else {
 9217                                            Color::Default
 9218                                        }),
 9219                                        None,
 9220                                        false,
 9221                                    ))),
 9222                            )
 9223                            .child(Label::new("Preview").into_any_element())
 9224                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9225                    )
 9226                })
 9227                .into_any(),
 9228        )
 9229    }
 9230
 9231    fn render_edit_prediction_cursor_popover_preview(
 9232        &self,
 9233        completion: &InlineCompletionState,
 9234        cursor_point: Point,
 9235        style: &EditorStyle,
 9236        cx: &mut Context<Editor>,
 9237    ) -> Option<Div> {
 9238        use text::ToPoint as _;
 9239
 9240        fn render_relative_row_jump(
 9241            prefix: impl Into<String>,
 9242            current_row: u32,
 9243            target_row: u32,
 9244        ) -> Div {
 9245            let (row_diff, arrow) = if target_row < current_row {
 9246                (current_row - target_row, IconName::ArrowUp)
 9247            } else {
 9248                (target_row - current_row, IconName::ArrowDown)
 9249            };
 9250
 9251            h_flex()
 9252                .child(
 9253                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9254                        .color(Color::Muted)
 9255                        .size(LabelSize::Small),
 9256                )
 9257                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9258        }
 9259
 9260        match &completion.completion {
 9261            InlineCompletion::Move {
 9262                target, snapshot, ..
 9263            } => Some(
 9264                h_flex()
 9265                    .px_2()
 9266                    .gap_2()
 9267                    .flex_1()
 9268                    .child(
 9269                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9270                            Icon::new(IconName::ZedPredictDown)
 9271                        } else {
 9272                            Icon::new(IconName::ZedPredictUp)
 9273                        },
 9274                    )
 9275                    .child(Label::new("Jump to Edit")),
 9276            ),
 9277
 9278            InlineCompletion::Edit {
 9279                edits,
 9280                edit_preview,
 9281                snapshot,
 9282                display_mode: _,
 9283            } => {
 9284                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9285
 9286                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9287                    &snapshot,
 9288                    &edits,
 9289                    edit_preview.as_ref()?,
 9290                    true,
 9291                    cx,
 9292                )
 9293                .first_line_preview();
 9294
 9295                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9296                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9297
 9298                let preview = h_flex()
 9299                    .gap_1()
 9300                    .min_w_16()
 9301                    .child(styled_text)
 9302                    .when(has_more_lines, |parent| parent.child(""));
 9303
 9304                let left = if first_edit_row != cursor_point.row {
 9305                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9306                        .into_any_element()
 9307                } else {
 9308                    Icon::new(IconName::ZedPredict).into_any_element()
 9309                };
 9310
 9311                Some(
 9312                    h_flex()
 9313                        .h_full()
 9314                        .flex_1()
 9315                        .gap_2()
 9316                        .pr_1()
 9317                        .overflow_x_hidden()
 9318                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9319                        .child(left)
 9320                        .child(preview),
 9321                )
 9322            }
 9323        }
 9324    }
 9325
 9326    pub fn render_context_menu(
 9327        &self,
 9328        style: &EditorStyle,
 9329        max_height_in_lines: u32,
 9330        window: &mut Window,
 9331        cx: &mut Context<Editor>,
 9332    ) -> Option<AnyElement> {
 9333        let menu = self.context_menu.borrow();
 9334        let menu = menu.as_ref()?;
 9335        if !menu.visible() {
 9336            return None;
 9337        };
 9338        Some(menu.render(style, max_height_in_lines, window, cx))
 9339    }
 9340
 9341    fn render_context_menu_aside(
 9342        &mut self,
 9343        max_size: Size<Pixels>,
 9344        window: &mut Window,
 9345        cx: &mut Context<Editor>,
 9346    ) -> Option<AnyElement> {
 9347        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9348            if menu.visible() {
 9349                menu.render_aside(max_size, window, cx)
 9350            } else {
 9351                None
 9352            }
 9353        })
 9354    }
 9355
 9356    fn hide_context_menu(
 9357        &mut self,
 9358        window: &mut Window,
 9359        cx: &mut Context<Self>,
 9360    ) -> Option<CodeContextMenu> {
 9361        cx.notify();
 9362        self.completion_tasks.clear();
 9363        let context_menu = self.context_menu.borrow_mut().take();
 9364        self.stale_inline_completion_in_menu.take();
 9365        self.update_visible_inline_completion(window, cx);
 9366        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9367            if let Some(completion_provider) = &self.completion_provider {
 9368                completion_provider.selection_changed(None, window, cx);
 9369            }
 9370        }
 9371        context_menu
 9372    }
 9373
 9374    fn show_snippet_choices(
 9375        &mut self,
 9376        choices: &Vec<String>,
 9377        selection: Range<Anchor>,
 9378        cx: &mut Context<Self>,
 9379    ) {
 9380        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9381            (Some(a), Some(b)) if a == b => a,
 9382            _ => {
 9383                log::error!("expected anchor range to have matching buffer IDs");
 9384                return;
 9385            }
 9386        };
 9387        let multi_buffer = self.buffer().read(cx);
 9388        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9389            return;
 9390        };
 9391
 9392        let id = post_inc(&mut self.next_completion_id);
 9393        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9394        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9395            CompletionsMenu::new_snippet_choices(
 9396                id,
 9397                true,
 9398                choices,
 9399                selection,
 9400                buffer,
 9401                snippet_sort_order,
 9402            ),
 9403        ));
 9404    }
 9405
 9406    pub fn insert_snippet(
 9407        &mut self,
 9408        insertion_ranges: &[Range<usize>],
 9409        snippet: Snippet,
 9410        window: &mut Window,
 9411        cx: &mut Context<Self>,
 9412    ) -> Result<()> {
 9413        struct Tabstop<T> {
 9414            is_end_tabstop: bool,
 9415            ranges: Vec<Range<T>>,
 9416            choices: Option<Vec<String>>,
 9417        }
 9418
 9419        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9420            let snippet_text: Arc<str> = snippet.text.clone().into();
 9421            let edits = insertion_ranges
 9422                .iter()
 9423                .cloned()
 9424                .map(|range| (range, snippet_text.clone()));
 9425            let autoindent_mode = AutoindentMode::Block {
 9426                original_indent_columns: Vec::new(),
 9427            };
 9428            buffer.edit(edits, Some(autoindent_mode), cx);
 9429
 9430            let snapshot = &*buffer.read(cx);
 9431            let snippet = &snippet;
 9432            snippet
 9433                .tabstops
 9434                .iter()
 9435                .map(|tabstop| {
 9436                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9437                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9438                    });
 9439                    let mut tabstop_ranges = tabstop
 9440                        .ranges
 9441                        .iter()
 9442                        .flat_map(|tabstop_range| {
 9443                            let mut delta = 0_isize;
 9444                            insertion_ranges.iter().map(move |insertion_range| {
 9445                                let insertion_start = insertion_range.start as isize + delta;
 9446                                delta +=
 9447                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9448
 9449                                let start = ((insertion_start + tabstop_range.start) as usize)
 9450                                    .min(snapshot.len());
 9451                                let end = ((insertion_start + tabstop_range.end) as usize)
 9452                                    .min(snapshot.len());
 9453                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9454                            })
 9455                        })
 9456                        .collect::<Vec<_>>();
 9457                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9458
 9459                    Tabstop {
 9460                        is_end_tabstop,
 9461                        ranges: tabstop_ranges,
 9462                        choices: tabstop.choices.clone(),
 9463                    }
 9464                })
 9465                .collect::<Vec<_>>()
 9466        });
 9467        if let Some(tabstop) = tabstops.first() {
 9468            self.change_selections(Default::default(), window, cx, |s| {
 9469                // Reverse order so that the first range is the newest created selection.
 9470                // Completions will use it and autoscroll will prioritize it.
 9471                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9472            });
 9473
 9474            if let Some(choices) = &tabstop.choices {
 9475                if let Some(selection) = tabstop.ranges.first() {
 9476                    self.show_snippet_choices(choices, selection.clone(), cx)
 9477                }
 9478            }
 9479
 9480            // If we're already at the last tabstop and it's at the end of the snippet,
 9481            // we're done, we don't need to keep the state around.
 9482            if !tabstop.is_end_tabstop {
 9483                let choices = tabstops
 9484                    .iter()
 9485                    .map(|tabstop| tabstop.choices.clone())
 9486                    .collect();
 9487
 9488                let ranges = tabstops
 9489                    .into_iter()
 9490                    .map(|tabstop| tabstop.ranges)
 9491                    .collect::<Vec<_>>();
 9492
 9493                self.snippet_stack.push(SnippetState {
 9494                    active_index: 0,
 9495                    ranges,
 9496                    choices,
 9497                });
 9498            }
 9499
 9500            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9501            if self.autoclose_regions.is_empty() {
 9502                let snapshot = self.buffer.read(cx).snapshot(cx);
 9503                for selection in &mut self.selections.all::<Point>(cx) {
 9504                    let selection_head = selection.head();
 9505                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9506                        continue;
 9507                    };
 9508
 9509                    let mut bracket_pair = None;
 9510                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9511                    let prev_chars = snapshot
 9512                        .reversed_chars_at(selection_head)
 9513                        .collect::<String>();
 9514                    for (pair, enabled) in scope.brackets() {
 9515                        if enabled
 9516                            && pair.close
 9517                            && prev_chars.starts_with(pair.start.as_str())
 9518                            && next_chars.starts_with(pair.end.as_str())
 9519                        {
 9520                            bracket_pair = Some(pair.clone());
 9521                            break;
 9522                        }
 9523                    }
 9524                    if let Some(pair) = bracket_pair {
 9525                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9526                        let autoclose_enabled =
 9527                            self.use_autoclose && snapshot_settings.use_autoclose;
 9528                        if autoclose_enabled {
 9529                            let start = snapshot.anchor_after(selection_head);
 9530                            let end = snapshot.anchor_after(selection_head);
 9531                            self.autoclose_regions.push(AutocloseRegion {
 9532                                selection_id: selection.id,
 9533                                range: start..end,
 9534                                pair,
 9535                            });
 9536                        }
 9537                    }
 9538                }
 9539            }
 9540        }
 9541        Ok(())
 9542    }
 9543
 9544    pub fn move_to_next_snippet_tabstop(
 9545        &mut self,
 9546        window: &mut Window,
 9547        cx: &mut Context<Self>,
 9548    ) -> bool {
 9549        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9550    }
 9551
 9552    pub fn move_to_prev_snippet_tabstop(
 9553        &mut self,
 9554        window: &mut Window,
 9555        cx: &mut Context<Self>,
 9556    ) -> bool {
 9557        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9558    }
 9559
 9560    pub fn move_to_snippet_tabstop(
 9561        &mut self,
 9562        bias: Bias,
 9563        window: &mut Window,
 9564        cx: &mut Context<Self>,
 9565    ) -> bool {
 9566        if let Some(mut snippet) = self.snippet_stack.pop() {
 9567            match bias {
 9568                Bias::Left => {
 9569                    if snippet.active_index > 0 {
 9570                        snippet.active_index -= 1;
 9571                    } else {
 9572                        self.snippet_stack.push(snippet);
 9573                        return false;
 9574                    }
 9575                }
 9576                Bias::Right => {
 9577                    if snippet.active_index + 1 < snippet.ranges.len() {
 9578                        snippet.active_index += 1;
 9579                    } else {
 9580                        self.snippet_stack.push(snippet);
 9581                        return false;
 9582                    }
 9583                }
 9584            }
 9585            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9586                self.change_selections(Default::default(), window, cx, |s| {
 9587                    // Reverse order so that the first range is the newest created selection.
 9588                    // Completions will use it and autoscroll will prioritize it.
 9589                    s.select_ranges(current_ranges.iter().rev().cloned())
 9590                });
 9591
 9592                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9593                    if let Some(selection) = current_ranges.first() {
 9594                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9595                    }
 9596                }
 9597
 9598                // If snippet state is not at the last tabstop, push it back on the stack
 9599                if snippet.active_index + 1 < snippet.ranges.len() {
 9600                    self.snippet_stack.push(snippet);
 9601                }
 9602                return true;
 9603            }
 9604        }
 9605
 9606        false
 9607    }
 9608
 9609    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9610        self.transact(window, cx, |this, window, cx| {
 9611            this.select_all(&SelectAll, window, cx);
 9612            this.insert("", window, cx);
 9613        });
 9614    }
 9615
 9616    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9617        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9618        self.transact(window, cx, |this, window, cx| {
 9619            this.select_autoclose_pair(window, cx);
 9620            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9621            if !this.linked_edit_ranges.is_empty() {
 9622                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9623                let snapshot = this.buffer.read(cx).snapshot(cx);
 9624
 9625                for selection in selections.iter() {
 9626                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9627                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9628                    if selection_start.buffer_id != selection_end.buffer_id {
 9629                        continue;
 9630                    }
 9631                    if let Some(ranges) =
 9632                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9633                    {
 9634                        for (buffer, entries) in ranges {
 9635                            linked_ranges.entry(buffer).or_default().extend(entries);
 9636                        }
 9637                    }
 9638                }
 9639            }
 9640
 9641            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9642            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9643            for selection in &mut selections {
 9644                if selection.is_empty() {
 9645                    let old_head = selection.head();
 9646                    let mut new_head =
 9647                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9648                            .to_point(&display_map);
 9649                    if let Some((buffer, line_buffer_range)) = display_map
 9650                        .buffer_snapshot
 9651                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9652                    {
 9653                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9654                        let indent_len = match indent_size.kind {
 9655                            IndentKind::Space => {
 9656                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9657                            }
 9658                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9659                        };
 9660                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9661                            let indent_len = indent_len.get();
 9662                            new_head = cmp::min(
 9663                                new_head,
 9664                                MultiBufferPoint::new(
 9665                                    old_head.row,
 9666                                    ((old_head.column - 1) / indent_len) * indent_len,
 9667                                ),
 9668                            );
 9669                        }
 9670                    }
 9671
 9672                    selection.set_head(new_head, SelectionGoal::None);
 9673                }
 9674            }
 9675
 9676            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9677            this.insert("", window, cx);
 9678            let empty_str: Arc<str> = Arc::from("");
 9679            for (buffer, edits) in linked_ranges {
 9680                let snapshot = buffer.read(cx).snapshot();
 9681                use text::ToPoint as TP;
 9682
 9683                let edits = edits
 9684                    .into_iter()
 9685                    .map(|range| {
 9686                        let end_point = TP::to_point(&range.end, &snapshot);
 9687                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9688
 9689                        if end_point == start_point {
 9690                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9691                                .saturating_sub(1);
 9692                            start_point =
 9693                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9694                        };
 9695
 9696                        (start_point..end_point, empty_str.clone())
 9697                    })
 9698                    .sorted_by_key(|(range, _)| range.start)
 9699                    .collect::<Vec<_>>();
 9700                buffer.update(cx, |this, cx| {
 9701                    this.edit(edits, None, cx);
 9702                })
 9703            }
 9704            this.refresh_inline_completion(true, false, window, cx);
 9705            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9706        });
 9707    }
 9708
 9709    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9710        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9711        self.transact(window, cx, |this, window, cx| {
 9712            this.change_selections(Default::default(), window, cx, |s| {
 9713                s.move_with(|map, selection| {
 9714                    if selection.is_empty() {
 9715                        let cursor = movement::right(map, selection.head());
 9716                        selection.end = cursor;
 9717                        selection.reversed = true;
 9718                        selection.goal = SelectionGoal::None;
 9719                    }
 9720                })
 9721            });
 9722            this.insert("", window, cx);
 9723            this.refresh_inline_completion(true, false, window, cx);
 9724        });
 9725    }
 9726
 9727    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9728        if self.mode.is_single_line() {
 9729            cx.propagate();
 9730            return;
 9731        }
 9732
 9733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9734        if self.move_to_prev_snippet_tabstop(window, cx) {
 9735            return;
 9736        }
 9737        self.outdent(&Outdent, window, cx);
 9738    }
 9739
 9740    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9741        if self.mode.is_single_line() {
 9742            cx.propagate();
 9743            return;
 9744        }
 9745
 9746        if self.move_to_next_snippet_tabstop(window, cx) {
 9747            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9748            return;
 9749        }
 9750        if self.read_only(cx) {
 9751            return;
 9752        }
 9753        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9754        let mut selections = self.selections.all_adjusted(cx);
 9755        let buffer = self.buffer.read(cx);
 9756        let snapshot = buffer.snapshot(cx);
 9757        let rows_iter = selections.iter().map(|s| s.head().row);
 9758        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9759
 9760        let has_some_cursor_in_whitespace = selections
 9761            .iter()
 9762            .filter(|selection| selection.is_empty())
 9763            .any(|selection| {
 9764                let cursor = selection.head();
 9765                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9766                cursor.column < current_indent.len
 9767            });
 9768
 9769        let mut edits = Vec::new();
 9770        let mut prev_edited_row = 0;
 9771        let mut row_delta = 0;
 9772        for selection in &mut selections {
 9773            if selection.start.row != prev_edited_row {
 9774                row_delta = 0;
 9775            }
 9776            prev_edited_row = selection.end.row;
 9777
 9778            // If the selection is non-empty, then increase the indentation of the selected lines.
 9779            if !selection.is_empty() {
 9780                row_delta =
 9781                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9782                continue;
 9783            }
 9784
 9785            let cursor = selection.head();
 9786            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9787            if let Some(suggested_indent) =
 9788                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9789            {
 9790                // Don't do anything if already at suggested indent
 9791                // and there is any other cursor which is not
 9792                if has_some_cursor_in_whitespace
 9793                    && cursor.column == current_indent.len
 9794                    && current_indent.len == suggested_indent.len
 9795                {
 9796                    continue;
 9797                }
 9798
 9799                // Adjust line and move cursor to suggested indent
 9800                // if cursor is not at suggested indent
 9801                if cursor.column < suggested_indent.len
 9802                    && cursor.column <= current_indent.len
 9803                    && current_indent.len <= suggested_indent.len
 9804                {
 9805                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9806                    selection.end = selection.start;
 9807                    if row_delta == 0 {
 9808                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9809                            cursor.row,
 9810                            current_indent,
 9811                            suggested_indent,
 9812                        ));
 9813                        row_delta = suggested_indent.len - current_indent.len;
 9814                    }
 9815                    continue;
 9816                }
 9817
 9818                // If current indent is more than suggested indent
 9819                // only move cursor to current indent and skip indent
 9820                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9821                    selection.start = Point::new(cursor.row, current_indent.len);
 9822                    selection.end = selection.start;
 9823                    continue;
 9824                }
 9825            }
 9826
 9827            // Otherwise, insert a hard or soft tab.
 9828            let settings = buffer.language_settings_at(cursor, cx);
 9829            let tab_size = if settings.hard_tabs {
 9830                IndentSize::tab()
 9831            } else {
 9832                let tab_size = settings.tab_size.get();
 9833                let indent_remainder = snapshot
 9834                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9835                    .flat_map(str::chars)
 9836                    .fold(row_delta % tab_size, |counter: u32, c| {
 9837                        if c == '\t' {
 9838                            0
 9839                        } else {
 9840                            (counter + 1) % tab_size
 9841                        }
 9842                    });
 9843
 9844                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9845                IndentSize::spaces(chars_to_next_tab_stop)
 9846            };
 9847            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9848            selection.end = selection.start;
 9849            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9850            row_delta += tab_size.len;
 9851        }
 9852
 9853        self.transact(window, cx, |this, window, cx| {
 9854            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9855            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9856            this.refresh_inline_completion(true, false, window, cx);
 9857        });
 9858    }
 9859
 9860    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9861        if self.read_only(cx) {
 9862            return;
 9863        }
 9864        if self.mode.is_single_line() {
 9865            cx.propagate();
 9866            return;
 9867        }
 9868
 9869        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9870        let mut selections = self.selections.all::<Point>(cx);
 9871        let mut prev_edited_row = 0;
 9872        let mut row_delta = 0;
 9873        let mut edits = Vec::new();
 9874        let buffer = self.buffer.read(cx);
 9875        let snapshot = buffer.snapshot(cx);
 9876        for selection in &mut selections {
 9877            if selection.start.row != prev_edited_row {
 9878                row_delta = 0;
 9879            }
 9880            prev_edited_row = selection.end.row;
 9881
 9882            row_delta =
 9883                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9884        }
 9885
 9886        self.transact(window, cx, |this, window, cx| {
 9887            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9888            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9889        });
 9890    }
 9891
 9892    fn indent_selection(
 9893        buffer: &MultiBuffer,
 9894        snapshot: &MultiBufferSnapshot,
 9895        selection: &mut Selection<Point>,
 9896        edits: &mut Vec<(Range<Point>, String)>,
 9897        delta_for_start_row: u32,
 9898        cx: &App,
 9899    ) -> u32 {
 9900        let settings = buffer.language_settings_at(selection.start, cx);
 9901        let tab_size = settings.tab_size.get();
 9902        let indent_kind = if settings.hard_tabs {
 9903            IndentKind::Tab
 9904        } else {
 9905            IndentKind::Space
 9906        };
 9907        let mut start_row = selection.start.row;
 9908        let mut end_row = selection.end.row + 1;
 9909
 9910        // If a selection ends at the beginning of a line, don't indent
 9911        // that last line.
 9912        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9913            end_row -= 1;
 9914        }
 9915
 9916        // Avoid re-indenting a row that has already been indented by a
 9917        // previous selection, but still update this selection's column
 9918        // to reflect that indentation.
 9919        if delta_for_start_row > 0 {
 9920            start_row += 1;
 9921            selection.start.column += delta_for_start_row;
 9922            if selection.end.row == selection.start.row {
 9923                selection.end.column += delta_for_start_row;
 9924            }
 9925        }
 9926
 9927        let mut delta_for_end_row = 0;
 9928        let has_multiple_rows = start_row + 1 != end_row;
 9929        for row in start_row..end_row {
 9930            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9931            let indent_delta = match (current_indent.kind, indent_kind) {
 9932                (IndentKind::Space, IndentKind::Space) => {
 9933                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9934                    IndentSize::spaces(columns_to_next_tab_stop)
 9935                }
 9936                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9937                (_, IndentKind::Tab) => IndentSize::tab(),
 9938            };
 9939
 9940            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9941                0
 9942            } else {
 9943                selection.start.column
 9944            };
 9945            let row_start = Point::new(row, start);
 9946            edits.push((
 9947                row_start..row_start,
 9948                indent_delta.chars().collect::<String>(),
 9949            ));
 9950
 9951            // Update this selection's endpoints to reflect the indentation.
 9952            if row == selection.start.row {
 9953                selection.start.column += indent_delta.len;
 9954            }
 9955            if row == selection.end.row {
 9956                selection.end.column += indent_delta.len;
 9957                delta_for_end_row = indent_delta.len;
 9958            }
 9959        }
 9960
 9961        if selection.start.row == selection.end.row {
 9962            delta_for_start_row + delta_for_end_row
 9963        } else {
 9964            delta_for_end_row
 9965        }
 9966    }
 9967
 9968    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9969        if self.read_only(cx) {
 9970            return;
 9971        }
 9972        if self.mode.is_single_line() {
 9973            cx.propagate();
 9974            return;
 9975        }
 9976
 9977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9978        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9979        let selections = self.selections.all::<Point>(cx);
 9980        let mut deletion_ranges = Vec::new();
 9981        let mut last_outdent = None;
 9982        {
 9983            let buffer = self.buffer.read(cx);
 9984            let snapshot = buffer.snapshot(cx);
 9985            for selection in &selections {
 9986                let settings = buffer.language_settings_at(selection.start, cx);
 9987                let tab_size = settings.tab_size.get();
 9988                let mut rows = selection.spanned_rows(false, &display_map);
 9989
 9990                // Avoid re-outdenting a row that has already been outdented by a
 9991                // previous selection.
 9992                if let Some(last_row) = last_outdent {
 9993                    if last_row == rows.start {
 9994                        rows.start = rows.start.next_row();
 9995                    }
 9996                }
 9997                let has_multiple_rows = rows.len() > 1;
 9998                for row in rows.iter_rows() {
 9999                    let indent_size = snapshot.indent_size_for_line(row);
10000                    if indent_size.len > 0 {
10001                        let deletion_len = match indent_size.kind {
10002                            IndentKind::Space => {
10003                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10004                                if columns_to_prev_tab_stop == 0 {
10005                                    tab_size
10006                                } else {
10007                                    columns_to_prev_tab_stop
10008                                }
10009                            }
10010                            IndentKind::Tab => 1,
10011                        };
10012                        let start = if has_multiple_rows
10013                            || deletion_len > selection.start.column
10014                            || indent_size.len < selection.start.column
10015                        {
10016                            0
10017                        } else {
10018                            selection.start.column - deletion_len
10019                        };
10020                        deletion_ranges.push(
10021                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10022                        );
10023                        last_outdent = Some(row);
10024                    }
10025                }
10026            }
10027        }
10028
10029        self.transact(window, cx, |this, window, cx| {
10030            this.buffer.update(cx, |buffer, cx| {
10031                let empty_str: Arc<str> = Arc::default();
10032                buffer.edit(
10033                    deletion_ranges
10034                        .into_iter()
10035                        .map(|range| (range, empty_str.clone())),
10036                    None,
10037                    cx,
10038                );
10039            });
10040            let selections = this.selections.all::<usize>(cx);
10041            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10042        });
10043    }
10044
10045    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10046        if self.read_only(cx) {
10047            return;
10048        }
10049        if self.mode.is_single_line() {
10050            cx.propagate();
10051            return;
10052        }
10053
10054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10055        let selections = self
10056            .selections
10057            .all::<usize>(cx)
10058            .into_iter()
10059            .map(|s| s.range());
10060
10061        self.transact(window, cx, |this, window, cx| {
10062            this.buffer.update(cx, |buffer, cx| {
10063                buffer.autoindent_ranges(selections, cx);
10064            });
10065            let selections = this.selections.all::<usize>(cx);
10066            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10067        });
10068    }
10069
10070    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10071        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10072        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10073        let selections = self.selections.all::<Point>(cx);
10074
10075        let mut new_cursors = Vec::new();
10076        let mut edit_ranges = Vec::new();
10077        let mut selections = selections.iter().peekable();
10078        while let Some(selection) = selections.next() {
10079            let mut rows = selection.spanned_rows(false, &display_map);
10080            let goal_display_column = selection.head().to_display_point(&display_map).column();
10081
10082            // Accumulate contiguous regions of rows that we want to delete.
10083            while let Some(next_selection) = selections.peek() {
10084                let next_rows = next_selection.spanned_rows(false, &display_map);
10085                if next_rows.start <= rows.end {
10086                    rows.end = next_rows.end;
10087                    selections.next().unwrap();
10088                } else {
10089                    break;
10090                }
10091            }
10092
10093            let buffer = &display_map.buffer_snapshot;
10094            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10095            let edit_end;
10096            let cursor_buffer_row;
10097            if buffer.max_point().row >= rows.end.0 {
10098                // If there's a line after the range, delete the \n from the end of the row range
10099                // and position the cursor on the next line.
10100                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10101                cursor_buffer_row = rows.end;
10102            } else {
10103                // If there isn't a line after the range, delete the \n from the line before the
10104                // start of the row range and position the cursor there.
10105                edit_start = edit_start.saturating_sub(1);
10106                edit_end = buffer.len();
10107                cursor_buffer_row = rows.start.previous_row();
10108            }
10109
10110            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10111            *cursor.column_mut() =
10112                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10113
10114            new_cursors.push((
10115                selection.id,
10116                buffer.anchor_after(cursor.to_point(&display_map)),
10117            ));
10118            edit_ranges.push(edit_start..edit_end);
10119        }
10120
10121        self.transact(window, cx, |this, window, cx| {
10122            let buffer = this.buffer.update(cx, |buffer, cx| {
10123                let empty_str: Arc<str> = Arc::default();
10124                buffer.edit(
10125                    edit_ranges
10126                        .into_iter()
10127                        .map(|range| (range, empty_str.clone())),
10128                    None,
10129                    cx,
10130                );
10131                buffer.snapshot(cx)
10132            });
10133            let new_selections = new_cursors
10134                .into_iter()
10135                .map(|(id, cursor)| {
10136                    let cursor = cursor.to_point(&buffer);
10137                    Selection {
10138                        id,
10139                        start: cursor,
10140                        end: cursor,
10141                        reversed: false,
10142                        goal: SelectionGoal::None,
10143                    }
10144                })
10145                .collect();
10146
10147            this.change_selections(Default::default(), window, cx, |s| {
10148                s.select(new_selections);
10149            });
10150        });
10151    }
10152
10153    pub fn join_lines_impl(
10154        &mut self,
10155        insert_whitespace: bool,
10156        window: &mut Window,
10157        cx: &mut Context<Self>,
10158    ) {
10159        if self.read_only(cx) {
10160            return;
10161        }
10162        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10163        for selection in self.selections.all::<Point>(cx) {
10164            let start = MultiBufferRow(selection.start.row);
10165            // Treat single line selections as if they include the next line. Otherwise this action
10166            // would do nothing for single line selections individual cursors.
10167            let end = if selection.start.row == selection.end.row {
10168                MultiBufferRow(selection.start.row + 1)
10169            } else {
10170                MultiBufferRow(selection.end.row)
10171            };
10172
10173            if let Some(last_row_range) = row_ranges.last_mut() {
10174                if start <= last_row_range.end {
10175                    last_row_range.end = end;
10176                    continue;
10177                }
10178            }
10179            row_ranges.push(start..end);
10180        }
10181
10182        let snapshot = self.buffer.read(cx).snapshot(cx);
10183        let mut cursor_positions = Vec::new();
10184        for row_range in &row_ranges {
10185            let anchor = snapshot.anchor_before(Point::new(
10186                row_range.end.previous_row().0,
10187                snapshot.line_len(row_range.end.previous_row()),
10188            ));
10189            cursor_positions.push(anchor..anchor);
10190        }
10191
10192        self.transact(window, cx, |this, window, cx| {
10193            for row_range in row_ranges.into_iter().rev() {
10194                for row in row_range.iter_rows().rev() {
10195                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10196                    let next_line_row = row.next_row();
10197                    let indent = snapshot.indent_size_for_line(next_line_row);
10198                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10199
10200                    let replace =
10201                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10202                            " "
10203                        } else {
10204                            ""
10205                        };
10206
10207                    this.buffer.update(cx, |buffer, cx| {
10208                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10209                    });
10210                }
10211            }
10212
10213            this.change_selections(Default::default(), window, cx, |s| {
10214                s.select_anchor_ranges(cursor_positions)
10215            });
10216        });
10217    }
10218
10219    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10220        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10221        self.join_lines_impl(true, window, cx);
10222    }
10223
10224    pub fn sort_lines_case_sensitive(
10225        &mut self,
10226        _: &SortLinesCaseSensitive,
10227        window: &mut Window,
10228        cx: &mut Context<Self>,
10229    ) {
10230        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10231    }
10232
10233    pub fn sort_lines_by_length(
10234        &mut self,
10235        _: &SortLinesByLength,
10236        window: &mut Window,
10237        cx: &mut Context<Self>,
10238    ) {
10239        self.manipulate_immutable_lines(window, cx, |lines| {
10240            lines.sort_by_key(|&line| line.chars().count())
10241        })
10242    }
10243
10244    pub fn sort_lines_case_insensitive(
10245        &mut self,
10246        _: &SortLinesCaseInsensitive,
10247        window: &mut Window,
10248        cx: &mut Context<Self>,
10249    ) {
10250        self.manipulate_immutable_lines(window, cx, |lines| {
10251            lines.sort_by_key(|line| line.to_lowercase())
10252        })
10253    }
10254
10255    pub fn unique_lines_case_insensitive(
10256        &mut self,
10257        _: &UniqueLinesCaseInsensitive,
10258        window: &mut Window,
10259        cx: &mut Context<Self>,
10260    ) {
10261        self.manipulate_immutable_lines(window, cx, |lines| {
10262            let mut seen = HashSet::default();
10263            lines.retain(|line| seen.insert(line.to_lowercase()));
10264        })
10265    }
10266
10267    pub fn unique_lines_case_sensitive(
10268        &mut self,
10269        _: &UniqueLinesCaseSensitive,
10270        window: &mut Window,
10271        cx: &mut Context<Self>,
10272    ) {
10273        self.manipulate_immutable_lines(window, cx, |lines| {
10274            let mut seen = HashSet::default();
10275            lines.retain(|line| seen.insert(*line));
10276        })
10277    }
10278
10279    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10280        let Some(project) = self.project.clone() else {
10281            return;
10282        };
10283        self.reload(project, window, cx)
10284            .detach_and_notify_err(window, cx);
10285    }
10286
10287    pub fn restore_file(
10288        &mut self,
10289        _: &::git::RestoreFile,
10290        window: &mut Window,
10291        cx: &mut Context<Self>,
10292    ) {
10293        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10294        let mut buffer_ids = HashSet::default();
10295        let snapshot = self.buffer().read(cx).snapshot(cx);
10296        for selection in self.selections.all::<usize>(cx) {
10297            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10298        }
10299
10300        let buffer = self.buffer().read(cx);
10301        let ranges = buffer_ids
10302            .into_iter()
10303            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10304            .collect::<Vec<_>>();
10305
10306        self.restore_hunks_in_ranges(ranges, window, cx);
10307    }
10308
10309    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10310        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10311        let selections = self
10312            .selections
10313            .all(cx)
10314            .into_iter()
10315            .map(|s| s.range())
10316            .collect();
10317        self.restore_hunks_in_ranges(selections, window, cx);
10318    }
10319
10320    pub fn restore_hunks_in_ranges(
10321        &mut self,
10322        ranges: Vec<Range<Point>>,
10323        window: &mut Window,
10324        cx: &mut Context<Editor>,
10325    ) {
10326        let mut revert_changes = HashMap::default();
10327        let chunk_by = self
10328            .snapshot(window, cx)
10329            .hunks_for_ranges(ranges)
10330            .into_iter()
10331            .chunk_by(|hunk| hunk.buffer_id);
10332        for (buffer_id, hunks) in &chunk_by {
10333            let hunks = hunks.collect::<Vec<_>>();
10334            for hunk in &hunks {
10335                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10336            }
10337            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10338        }
10339        drop(chunk_by);
10340        if !revert_changes.is_empty() {
10341            self.transact(window, cx, |editor, window, cx| {
10342                editor.restore(revert_changes, window, cx);
10343            });
10344        }
10345    }
10346
10347    pub fn open_active_item_in_terminal(
10348        &mut self,
10349        _: &OpenInTerminal,
10350        window: &mut Window,
10351        cx: &mut Context<Self>,
10352    ) {
10353        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10354            let project_path = buffer.read(cx).project_path(cx)?;
10355            let project = self.project.as_ref()?.read(cx);
10356            let entry = project.entry_for_path(&project_path, cx)?;
10357            let parent = match &entry.canonical_path {
10358                Some(canonical_path) => canonical_path.to_path_buf(),
10359                None => project.absolute_path(&project_path, cx)?,
10360            }
10361            .parent()?
10362            .to_path_buf();
10363            Some(parent)
10364        }) {
10365            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10366        }
10367    }
10368
10369    fn set_breakpoint_context_menu(
10370        &mut self,
10371        display_row: DisplayRow,
10372        position: Option<Anchor>,
10373        clicked_point: gpui::Point<Pixels>,
10374        window: &mut Window,
10375        cx: &mut Context<Self>,
10376    ) {
10377        let source = self
10378            .buffer
10379            .read(cx)
10380            .snapshot(cx)
10381            .anchor_before(Point::new(display_row.0, 0u32));
10382
10383        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10384
10385        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10386            self,
10387            source,
10388            clicked_point,
10389            context_menu,
10390            window,
10391            cx,
10392        );
10393    }
10394
10395    fn add_edit_breakpoint_block(
10396        &mut self,
10397        anchor: Anchor,
10398        breakpoint: &Breakpoint,
10399        edit_action: BreakpointPromptEditAction,
10400        window: &mut Window,
10401        cx: &mut Context<Self>,
10402    ) {
10403        let weak_editor = cx.weak_entity();
10404        let bp_prompt = cx.new(|cx| {
10405            BreakpointPromptEditor::new(
10406                weak_editor,
10407                anchor,
10408                breakpoint.clone(),
10409                edit_action,
10410                window,
10411                cx,
10412            )
10413        });
10414
10415        let height = bp_prompt.update(cx, |this, cx| {
10416            this.prompt
10417                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10418        });
10419        let cloned_prompt = bp_prompt.clone();
10420        let blocks = vec![BlockProperties {
10421            style: BlockStyle::Sticky,
10422            placement: BlockPlacement::Above(anchor),
10423            height: Some(height),
10424            render: Arc::new(move |cx| {
10425                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10426                cloned_prompt.clone().into_any_element()
10427            }),
10428            priority: 0,
10429            render_in_minimap: true,
10430        }];
10431
10432        let focus_handle = bp_prompt.focus_handle(cx);
10433        window.focus(&focus_handle);
10434
10435        let block_ids = self.insert_blocks(blocks, None, cx);
10436        bp_prompt.update(cx, |prompt, _| {
10437            prompt.add_block_ids(block_ids);
10438        });
10439    }
10440
10441    pub(crate) fn breakpoint_at_row(
10442        &self,
10443        row: u32,
10444        window: &mut Window,
10445        cx: &mut Context<Self>,
10446    ) -> Option<(Anchor, Breakpoint)> {
10447        let snapshot = self.snapshot(window, cx);
10448        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10449
10450        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10451    }
10452
10453    pub(crate) fn breakpoint_at_anchor(
10454        &self,
10455        breakpoint_position: Anchor,
10456        snapshot: &EditorSnapshot,
10457        cx: &mut Context<Self>,
10458    ) -> Option<(Anchor, Breakpoint)> {
10459        let project = self.project.clone()?;
10460
10461        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10462            snapshot
10463                .buffer_snapshot
10464                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10465        })?;
10466
10467        let enclosing_excerpt = breakpoint_position.excerpt_id;
10468        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10469        let buffer_snapshot = buffer.read(cx).snapshot();
10470
10471        let row = buffer_snapshot
10472            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10473            .row;
10474
10475        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10476        let anchor_end = snapshot
10477            .buffer_snapshot
10478            .anchor_after(Point::new(row, line_len));
10479
10480        let bp = self
10481            .breakpoint_store
10482            .as_ref()?
10483            .read_with(cx, |breakpoint_store, cx| {
10484                breakpoint_store
10485                    .breakpoints(
10486                        &buffer,
10487                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10488                        &buffer_snapshot,
10489                        cx,
10490                    )
10491                    .next()
10492                    .and_then(|(bp, _)| {
10493                        let breakpoint_row = buffer_snapshot
10494                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10495                            .row;
10496
10497                        if breakpoint_row == row {
10498                            snapshot
10499                                .buffer_snapshot
10500                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10501                                .map(|position| (position, bp.bp.clone()))
10502                        } else {
10503                            None
10504                        }
10505                    })
10506            });
10507        bp
10508    }
10509
10510    pub fn edit_log_breakpoint(
10511        &mut self,
10512        _: &EditLogBreakpoint,
10513        window: &mut Window,
10514        cx: &mut Context<Self>,
10515    ) {
10516        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10517            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10518                message: None,
10519                state: BreakpointState::Enabled,
10520                condition: None,
10521                hit_condition: None,
10522            });
10523
10524            self.add_edit_breakpoint_block(
10525                anchor,
10526                &breakpoint,
10527                BreakpointPromptEditAction::Log,
10528                window,
10529                cx,
10530            );
10531        }
10532    }
10533
10534    fn breakpoints_at_cursors(
10535        &self,
10536        window: &mut Window,
10537        cx: &mut Context<Self>,
10538    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10539        let snapshot = self.snapshot(window, cx);
10540        let cursors = self
10541            .selections
10542            .disjoint_anchors()
10543            .into_iter()
10544            .map(|selection| {
10545                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10546
10547                let breakpoint_position = self
10548                    .breakpoint_at_row(cursor_position.row, window, cx)
10549                    .map(|bp| bp.0)
10550                    .unwrap_or_else(|| {
10551                        snapshot
10552                            .display_snapshot
10553                            .buffer_snapshot
10554                            .anchor_after(Point::new(cursor_position.row, 0))
10555                    });
10556
10557                let breakpoint = self
10558                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10559                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10560
10561                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10562            })
10563            // 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.
10564            .collect::<HashMap<Anchor, _>>();
10565
10566        cursors.into_iter().collect()
10567    }
10568
10569    pub fn enable_breakpoint(
10570        &mut self,
10571        _: &crate::actions::EnableBreakpoint,
10572        window: &mut Window,
10573        cx: &mut Context<Self>,
10574    ) {
10575        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10576            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10577                continue;
10578            };
10579            self.edit_breakpoint_at_anchor(
10580                anchor,
10581                breakpoint,
10582                BreakpointEditAction::InvertState,
10583                cx,
10584            );
10585        }
10586    }
10587
10588    pub fn disable_breakpoint(
10589        &mut self,
10590        _: &crate::actions::DisableBreakpoint,
10591        window: &mut Window,
10592        cx: &mut Context<Self>,
10593    ) {
10594        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10595            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10596                continue;
10597            };
10598            self.edit_breakpoint_at_anchor(
10599                anchor,
10600                breakpoint,
10601                BreakpointEditAction::InvertState,
10602                cx,
10603            );
10604        }
10605    }
10606
10607    pub fn toggle_breakpoint(
10608        &mut self,
10609        _: &crate::actions::ToggleBreakpoint,
10610        window: &mut Window,
10611        cx: &mut Context<Self>,
10612    ) {
10613        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10614            if let Some(breakpoint) = breakpoint {
10615                self.edit_breakpoint_at_anchor(
10616                    anchor,
10617                    breakpoint,
10618                    BreakpointEditAction::Toggle,
10619                    cx,
10620                );
10621            } else {
10622                self.edit_breakpoint_at_anchor(
10623                    anchor,
10624                    Breakpoint::new_standard(),
10625                    BreakpointEditAction::Toggle,
10626                    cx,
10627                );
10628            }
10629        }
10630    }
10631
10632    pub fn edit_breakpoint_at_anchor(
10633        &mut self,
10634        breakpoint_position: Anchor,
10635        breakpoint: Breakpoint,
10636        edit_action: BreakpointEditAction,
10637        cx: &mut Context<Self>,
10638    ) {
10639        let Some(breakpoint_store) = &self.breakpoint_store else {
10640            return;
10641        };
10642
10643        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10644            if breakpoint_position == Anchor::min() {
10645                self.buffer()
10646                    .read(cx)
10647                    .excerpt_buffer_ids()
10648                    .into_iter()
10649                    .next()
10650            } else {
10651                None
10652            }
10653        }) else {
10654            return;
10655        };
10656
10657        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10658            return;
10659        };
10660
10661        breakpoint_store.update(cx, |breakpoint_store, cx| {
10662            breakpoint_store.toggle_breakpoint(
10663                buffer,
10664                BreakpointWithPosition {
10665                    position: breakpoint_position.text_anchor,
10666                    bp: breakpoint,
10667                },
10668                edit_action,
10669                cx,
10670            );
10671        });
10672
10673        cx.notify();
10674    }
10675
10676    #[cfg(any(test, feature = "test-support"))]
10677    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10678        self.breakpoint_store.clone()
10679    }
10680
10681    pub fn prepare_restore_change(
10682        &self,
10683        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10684        hunk: &MultiBufferDiffHunk,
10685        cx: &mut App,
10686    ) -> Option<()> {
10687        if hunk.is_created_file() {
10688            return None;
10689        }
10690        let buffer = self.buffer.read(cx);
10691        let diff = buffer.diff_for(hunk.buffer_id)?;
10692        let buffer = buffer.buffer(hunk.buffer_id)?;
10693        let buffer = buffer.read(cx);
10694        let original_text = diff
10695            .read(cx)
10696            .base_text()
10697            .as_rope()
10698            .slice(hunk.diff_base_byte_range.clone());
10699        let buffer_snapshot = buffer.snapshot();
10700        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10701        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10702            probe
10703                .0
10704                .start
10705                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10706                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10707        }) {
10708            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10709            Some(())
10710        } else {
10711            None
10712        }
10713    }
10714
10715    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10716        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10717    }
10718
10719    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10720        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10721    }
10722
10723    fn manipulate_lines<M>(
10724        &mut self,
10725        window: &mut Window,
10726        cx: &mut Context<Self>,
10727        mut manipulate: M,
10728    ) where
10729        M: FnMut(&str) -> LineManipulationResult,
10730    {
10731        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10732
10733        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10734        let buffer = self.buffer.read(cx).snapshot(cx);
10735
10736        let mut edits = Vec::new();
10737
10738        let selections = self.selections.all::<Point>(cx);
10739        let mut selections = selections.iter().peekable();
10740        let mut contiguous_row_selections = Vec::new();
10741        let mut new_selections = Vec::new();
10742        let mut added_lines = 0;
10743        let mut removed_lines = 0;
10744
10745        while let Some(selection) = selections.next() {
10746            let (start_row, end_row) = consume_contiguous_rows(
10747                &mut contiguous_row_selections,
10748                selection,
10749                &display_map,
10750                &mut selections,
10751            );
10752
10753            let start_point = Point::new(start_row.0, 0);
10754            let end_point = Point::new(
10755                end_row.previous_row().0,
10756                buffer.line_len(end_row.previous_row()),
10757            );
10758            let text = buffer
10759                .text_for_range(start_point..end_point)
10760                .collect::<String>();
10761
10762            let LineManipulationResult {
10763                new_text,
10764                line_count_before,
10765                line_count_after,
10766            } = manipulate(&text);
10767
10768            edits.push((start_point..end_point, new_text));
10769
10770            // Selections must change based on added and removed line count
10771            let start_row =
10772                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10773            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10774            new_selections.push(Selection {
10775                id: selection.id,
10776                start: start_row,
10777                end: end_row,
10778                goal: SelectionGoal::None,
10779                reversed: selection.reversed,
10780            });
10781
10782            if line_count_after > line_count_before {
10783                added_lines += line_count_after - line_count_before;
10784            } else if line_count_before > line_count_after {
10785                removed_lines += line_count_before - line_count_after;
10786            }
10787        }
10788
10789        self.transact(window, cx, |this, window, cx| {
10790            let buffer = this.buffer.update(cx, |buffer, cx| {
10791                buffer.edit(edits, None, cx);
10792                buffer.snapshot(cx)
10793            });
10794
10795            // Recalculate offsets on newly edited buffer
10796            let new_selections = new_selections
10797                .iter()
10798                .map(|s| {
10799                    let start_point = Point::new(s.start.0, 0);
10800                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10801                    Selection {
10802                        id: s.id,
10803                        start: buffer.point_to_offset(start_point),
10804                        end: buffer.point_to_offset(end_point),
10805                        goal: s.goal,
10806                        reversed: s.reversed,
10807                    }
10808                })
10809                .collect();
10810
10811            this.change_selections(Default::default(), window, cx, |s| {
10812                s.select(new_selections);
10813            });
10814
10815            this.request_autoscroll(Autoscroll::fit(), cx);
10816        });
10817    }
10818
10819    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10820        self.manipulate_text(window, cx, |text| {
10821            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10822            if has_upper_case_characters {
10823                text.to_lowercase()
10824            } else {
10825                text.to_uppercase()
10826            }
10827        })
10828    }
10829
10830    fn manipulate_immutable_lines<Fn>(
10831        &mut self,
10832        window: &mut Window,
10833        cx: &mut Context<Self>,
10834        mut callback: Fn,
10835    ) where
10836        Fn: FnMut(&mut Vec<&str>),
10837    {
10838        self.manipulate_lines(window, cx, |text| {
10839            let mut lines: Vec<&str> = text.split('\n').collect();
10840            let line_count_before = lines.len();
10841
10842            callback(&mut lines);
10843
10844            LineManipulationResult {
10845                new_text: lines.join("\n"),
10846                line_count_before,
10847                line_count_after: lines.len(),
10848            }
10849        });
10850    }
10851
10852    fn manipulate_mutable_lines<Fn>(
10853        &mut self,
10854        window: &mut Window,
10855        cx: &mut Context<Self>,
10856        mut callback: Fn,
10857    ) where
10858        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10859    {
10860        self.manipulate_lines(window, cx, |text| {
10861            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10862            let line_count_before = lines.len();
10863
10864            callback(&mut lines);
10865
10866            LineManipulationResult {
10867                new_text: lines.join("\n"),
10868                line_count_before,
10869                line_count_after: lines.len(),
10870            }
10871        });
10872    }
10873
10874    pub fn convert_indentation_to_spaces(
10875        &mut self,
10876        _: &ConvertIndentationToSpaces,
10877        window: &mut Window,
10878        cx: &mut Context<Self>,
10879    ) {
10880        let settings = self.buffer.read(cx).language_settings(cx);
10881        let tab_size = settings.tab_size.get() as usize;
10882
10883        self.manipulate_mutable_lines(window, cx, |lines| {
10884            // Allocates a reasonably sized scratch buffer once for the whole loop
10885            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10886            // Avoids recomputing spaces that could be inserted many times
10887            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10888                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10889                .collect();
10890
10891            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10892                let mut chars = line.as_ref().chars();
10893                let mut col = 0;
10894                let mut changed = false;
10895
10896                while let Some(ch) = chars.next() {
10897                    match ch {
10898                        ' ' => {
10899                            reindented_line.push(' ');
10900                            col += 1;
10901                        }
10902                        '\t' => {
10903                            // \t are converted to spaces depending on the current column
10904                            let spaces_len = tab_size - (col % tab_size);
10905                            reindented_line.extend(&space_cache[spaces_len - 1]);
10906                            col += spaces_len;
10907                            changed = true;
10908                        }
10909                        _ => {
10910                            // If we dont append before break, the character is consumed
10911                            reindented_line.push(ch);
10912                            break;
10913                        }
10914                    }
10915                }
10916
10917                if !changed {
10918                    reindented_line.clear();
10919                    continue;
10920                }
10921                // Append the rest of the line and replace old reference with new one
10922                reindented_line.extend(chars);
10923                *line = Cow::Owned(reindented_line.clone());
10924                reindented_line.clear();
10925            }
10926        });
10927    }
10928
10929    pub fn convert_indentation_to_tabs(
10930        &mut self,
10931        _: &ConvertIndentationToTabs,
10932        window: &mut Window,
10933        cx: &mut Context<Self>,
10934    ) {
10935        let settings = self.buffer.read(cx).language_settings(cx);
10936        let tab_size = settings.tab_size.get() as usize;
10937
10938        self.manipulate_mutable_lines(window, cx, |lines| {
10939            // Allocates a reasonably sized buffer once for the whole loop
10940            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10941            // Avoids recomputing spaces that could be inserted many times
10942            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10943                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10944                .collect();
10945
10946            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10947                let mut chars = line.chars();
10948                let mut spaces_count = 0;
10949                let mut first_non_indent_char = None;
10950                let mut changed = false;
10951
10952                while let Some(ch) = chars.next() {
10953                    match ch {
10954                        ' ' => {
10955                            // Keep track of spaces. Append \t when we reach tab_size
10956                            spaces_count += 1;
10957                            changed = true;
10958                            if spaces_count == tab_size {
10959                                reindented_line.push('\t');
10960                                spaces_count = 0;
10961                            }
10962                        }
10963                        '\t' => {
10964                            reindented_line.push('\t');
10965                            spaces_count = 0;
10966                        }
10967                        _ => {
10968                            // Dont append it yet, we might have remaining spaces
10969                            first_non_indent_char = Some(ch);
10970                            break;
10971                        }
10972                    }
10973                }
10974
10975                if !changed {
10976                    reindented_line.clear();
10977                    continue;
10978                }
10979                // Remaining spaces that didn't make a full tab stop
10980                if spaces_count > 0 {
10981                    reindented_line.extend(&space_cache[spaces_count - 1]);
10982                }
10983                // If we consume an extra character that was not indentation, add it back
10984                if let Some(extra_char) = first_non_indent_char {
10985                    reindented_line.push(extra_char);
10986                }
10987                // Append the rest of the line and replace old reference with new one
10988                reindented_line.extend(chars);
10989                *line = Cow::Owned(reindented_line.clone());
10990                reindented_line.clear();
10991            }
10992        });
10993    }
10994
10995    pub fn convert_to_upper_case(
10996        &mut self,
10997        _: &ConvertToUpperCase,
10998        window: &mut Window,
10999        cx: &mut Context<Self>,
11000    ) {
11001        self.manipulate_text(window, cx, |text| text.to_uppercase())
11002    }
11003
11004    pub fn convert_to_lower_case(
11005        &mut self,
11006        _: &ConvertToLowerCase,
11007        window: &mut Window,
11008        cx: &mut Context<Self>,
11009    ) {
11010        self.manipulate_text(window, cx, |text| text.to_lowercase())
11011    }
11012
11013    pub fn convert_to_title_case(
11014        &mut self,
11015        _: &ConvertToTitleCase,
11016        window: &mut Window,
11017        cx: &mut Context<Self>,
11018    ) {
11019        self.manipulate_text(window, cx, |text| {
11020            text.split('\n')
11021                .map(|line| line.to_case(Case::Title))
11022                .join("\n")
11023        })
11024    }
11025
11026    pub fn convert_to_snake_case(
11027        &mut self,
11028        _: &ConvertToSnakeCase,
11029        window: &mut Window,
11030        cx: &mut Context<Self>,
11031    ) {
11032        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11033    }
11034
11035    pub fn convert_to_kebab_case(
11036        &mut self,
11037        _: &ConvertToKebabCase,
11038        window: &mut Window,
11039        cx: &mut Context<Self>,
11040    ) {
11041        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11042    }
11043
11044    pub fn convert_to_upper_camel_case(
11045        &mut self,
11046        _: &ConvertToUpperCamelCase,
11047        window: &mut Window,
11048        cx: &mut Context<Self>,
11049    ) {
11050        self.manipulate_text(window, cx, |text| {
11051            text.split('\n')
11052                .map(|line| line.to_case(Case::UpperCamel))
11053                .join("\n")
11054        })
11055    }
11056
11057    pub fn convert_to_lower_camel_case(
11058        &mut self,
11059        _: &ConvertToLowerCamelCase,
11060        window: &mut Window,
11061        cx: &mut Context<Self>,
11062    ) {
11063        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11064    }
11065
11066    pub fn convert_to_opposite_case(
11067        &mut self,
11068        _: &ConvertToOppositeCase,
11069        window: &mut Window,
11070        cx: &mut Context<Self>,
11071    ) {
11072        self.manipulate_text(window, cx, |text| {
11073            text.chars()
11074                .fold(String::with_capacity(text.len()), |mut t, c| {
11075                    if c.is_uppercase() {
11076                        t.extend(c.to_lowercase());
11077                    } else {
11078                        t.extend(c.to_uppercase());
11079                    }
11080                    t
11081                })
11082        })
11083    }
11084
11085    pub fn convert_to_rot13(
11086        &mut self,
11087        _: &ConvertToRot13,
11088        window: &mut Window,
11089        cx: &mut Context<Self>,
11090    ) {
11091        self.manipulate_text(window, cx, |text| {
11092            text.chars()
11093                .map(|c| match c {
11094                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11095                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11096                    _ => c,
11097                })
11098                .collect()
11099        })
11100    }
11101
11102    pub fn convert_to_rot47(
11103        &mut self,
11104        _: &ConvertToRot47,
11105        window: &mut Window,
11106        cx: &mut Context<Self>,
11107    ) {
11108        self.manipulate_text(window, cx, |text| {
11109            text.chars()
11110                .map(|c| {
11111                    let code_point = c as u32;
11112                    if code_point >= 33 && code_point <= 126 {
11113                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11114                    }
11115                    c
11116                })
11117                .collect()
11118        })
11119    }
11120
11121    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11122    where
11123        Fn: FnMut(&str) -> String,
11124    {
11125        let buffer = self.buffer.read(cx).snapshot(cx);
11126
11127        let mut new_selections = Vec::new();
11128        let mut edits = Vec::new();
11129        let mut selection_adjustment = 0i32;
11130
11131        for selection in self.selections.all::<usize>(cx) {
11132            let selection_is_empty = selection.is_empty();
11133
11134            let (start, end) = if selection_is_empty {
11135                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11136                (word_range.start, word_range.end)
11137            } else {
11138                (selection.start, selection.end)
11139            };
11140
11141            let text = buffer.text_for_range(start..end).collect::<String>();
11142            let old_length = text.len() as i32;
11143            let text = callback(&text);
11144
11145            new_selections.push(Selection {
11146                start: (start as i32 - selection_adjustment) as usize,
11147                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11148                goal: SelectionGoal::None,
11149                ..selection
11150            });
11151
11152            selection_adjustment += old_length - text.len() as i32;
11153
11154            edits.push((start..end, text));
11155        }
11156
11157        self.transact(window, cx, |this, window, cx| {
11158            this.buffer.update(cx, |buffer, cx| {
11159                buffer.edit(edits, None, cx);
11160            });
11161
11162            this.change_selections(Default::default(), window, cx, |s| {
11163                s.select(new_selections);
11164            });
11165
11166            this.request_autoscroll(Autoscroll::fit(), cx);
11167        });
11168    }
11169
11170    pub fn move_selection_on_drop(
11171        &mut self,
11172        selection: &Selection<Anchor>,
11173        target: DisplayPoint,
11174        is_cut: bool,
11175        window: &mut Window,
11176        cx: &mut Context<Self>,
11177    ) {
11178        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11179        let buffer = &display_map.buffer_snapshot;
11180        let mut edits = Vec::new();
11181        let insert_point = display_map
11182            .clip_point(target, Bias::Left)
11183            .to_point(&display_map);
11184        let text = buffer
11185            .text_for_range(selection.start..selection.end)
11186            .collect::<String>();
11187        if is_cut {
11188            edits.push(((selection.start..selection.end), String::new()));
11189        }
11190        let insert_anchor = buffer.anchor_before(insert_point);
11191        edits.push(((insert_anchor..insert_anchor), text));
11192        let last_edit_start = insert_anchor.bias_left(buffer);
11193        let last_edit_end = insert_anchor.bias_right(buffer);
11194        self.transact(window, cx, |this, window, cx| {
11195            this.buffer.update(cx, |buffer, cx| {
11196                buffer.edit(edits, None, cx);
11197            });
11198            this.change_selections(Default::default(), window, cx, |s| {
11199                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11200            });
11201        });
11202    }
11203
11204    pub fn clear_selection_drag_state(&mut self) {
11205        self.selection_drag_state = SelectionDragState::None;
11206    }
11207
11208    pub fn duplicate(
11209        &mut self,
11210        upwards: bool,
11211        whole_lines: bool,
11212        window: &mut Window,
11213        cx: &mut Context<Self>,
11214    ) {
11215        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11216
11217        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11218        let buffer = &display_map.buffer_snapshot;
11219        let selections = self.selections.all::<Point>(cx);
11220
11221        let mut edits = Vec::new();
11222        let mut selections_iter = selections.iter().peekable();
11223        while let Some(selection) = selections_iter.next() {
11224            let mut rows = selection.spanned_rows(false, &display_map);
11225            // duplicate line-wise
11226            if whole_lines || selection.start == selection.end {
11227                // Avoid duplicating the same lines twice.
11228                while let Some(next_selection) = selections_iter.peek() {
11229                    let next_rows = next_selection.spanned_rows(false, &display_map);
11230                    if next_rows.start < rows.end {
11231                        rows.end = next_rows.end;
11232                        selections_iter.next().unwrap();
11233                    } else {
11234                        break;
11235                    }
11236                }
11237
11238                // Copy the text from the selected row region and splice it either at the start
11239                // or end of the region.
11240                let start = Point::new(rows.start.0, 0);
11241                let end = Point::new(
11242                    rows.end.previous_row().0,
11243                    buffer.line_len(rows.end.previous_row()),
11244                );
11245                let text = buffer
11246                    .text_for_range(start..end)
11247                    .chain(Some("\n"))
11248                    .collect::<String>();
11249                let insert_location = if upwards {
11250                    Point::new(rows.end.0, 0)
11251                } else {
11252                    start
11253                };
11254                edits.push((insert_location..insert_location, text));
11255            } else {
11256                // duplicate character-wise
11257                let start = selection.start;
11258                let end = selection.end;
11259                let text = buffer.text_for_range(start..end).collect::<String>();
11260                edits.push((selection.end..selection.end, text));
11261            }
11262        }
11263
11264        self.transact(window, cx, |this, _, cx| {
11265            this.buffer.update(cx, |buffer, cx| {
11266                buffer.edit(edits, None, cx);
11267            });
11268
11269            this.request_autoscroll(Autoscroll::fit(), cx);
11270        });
11271    }
11272
11273    pub fn duplicate_line_up(
11274        &mut self,
11275        _: &DuplicateLineUp,
11276        window: &mut Window,
11277        cx: &mut Context<Self>,
11278    ) {
11279        self.duplicate(true, true, window, cx);
11280    }
11281
11282    pub fn duplicate_line_down(
11283        &mut self,
11284        _: &DuplicateLineDown,
11285        window: &mut Window,
11286        cx: &mut Context<Self>,
11287    ) {
11288        self.duplicate(false, true, window, cx);
11289    }
11290
11291    pub fn duplicate_selection(
11292        &mut self,
11293        _: &DuplicateSelection,
11294        window: &mut Window,
11295        cx: &mut Context<Self>,
11296    ) {
11297        self.duplicate(false, false, window, cx);
11298    }
11299
11300    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11302        if self.mode.is_single_line() {
11303            cx.propagate();
11304            return;
11305        }
11306
11307        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11308        let buffer = self.buffer.read(cx).snapshot(cx);
11309
11310        let mut edits = Vec::new();
11311        let mut unfold_ranges = Vec::new();
11312        let mut refold_creases = Vec::new();
11313
11314        let selections = self.selections.all::<Point>(cx);
11315        let mut selections = selections.iter().peekable();
11316        let mut contiguous_row_selections = Vec::new();
11317        let mut new_selections = Vec::new();
11318
11319        while let Some(selection) = selections.next() {
11320            // Find all the selections that span a contiguous row range
11321            let (start_row, end_row) = consume_contiguous_rows(
11322                &mut contiguous_row_selections,
11323                selection,
11324                &display_map,
11325                &mut selections,
11326            );
11327
11328            // Move the text spanned by the row range to be before the line preceding the row range
11329            if start_row.0 > 0 {
11330                let range_to_move = Point::new(
11331                    start_row.previous_row().0,
11332                    buffer.line_len(start_row.previous_row()),
11333                )
11334                    ..Point::new(
11335                        end_row.previous_row().0,
11336                        buffer.line_len(end_row.previous_row()),
11337                    );
11338                let insertion_point = display_map
11339                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11340                    .0;
11341
11342                // Don't move lines across excerpts
11343                if buffer
11344                    .excerpt_containing(insertion_point..range_to_move.end)
11345                    .is_some()
11346                {
11347                    let text = buffer
11348                        .text_for_range(range_to_move.clone())
11349                        .flat_map(|s| s.chars())
11350                        .skip(1)
11351                        .chain(['\n'])
11352                        .collect::<String>();
11353
11354                    edits.push((
11355                        buffer.anchor_after(range_to_move.start)
11356                            ..buffer.anchor_before(range_to_move.end),
11357                        String::new(),
11358                    ));
11359                    let insertion_anchor = buffer.anchor_after(insertion_point);
11360                    edits.push((insertion_anchor..insertion_anchor, text));
11361
11362                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11363
11364                    // Move selections up
11365                    new_selections.extend(contiguous_row_selections.drain(..).map(
11366                        |mut selection| {
11367                            selection.start.row -= row_delta;
11368                            selection.end.row -= row_delta;
11369                            selection
11370                        },
11371                    ));
11372
11373                    // Move folds up
11374                    unfold_ranges.push(range_to_move.clone());
11375                    for fold in display_map.folds_in_range(
11376                        buffer.anchor_before(range_to_move.start)
11377                            ..buffer.anchor_after(range_to_move.end),
11378                    ) {
11379                        let mut start = fold.range.start.to_point(&buffer);
11380                        let mut end = fold.range.end.to_point(&buffer);
11381                        start.row -= row_delta;
11382                        end.row -= row_delta;
11383                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11384                    }
11385                }
11386            }
11387
11388            // If we didn't move line(s), preserve the existing selections
11389            new_selections.append(&mut contiguous_row_selections);
11390        }
11391
11392        self.transact(window, cx, |this, window, cx| {
11393            this.unfold_ranges(&unfold_ranges, true, true, cx);
11394            this.buffer.update(cx, |buffer, cx| {
11395                for (range, text) in edits {
11396                    buffer.edit([(range, text)], None, cx);
11397                }
11398            });
11399            this.fold_creases(refold_creases, true, window, cx);
11400            this.change_selections(Default::default(), window, cx, |s| {
11401                s.select(new_selections);
11402            })
11403        });
11404    }
11405
11406    pub fn move_line_down(
11407        &mut self,
11408        _: &MoveLineDown,
11409        window: &mut Window,
11410        cx: &mut Context<Self>,
11411    ) {
11412        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11413        if self.mode.is_single_line() {
11414            cx.propagate();
11415            return;
11416        }
11417
11418        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11419        let buffer = self.buffer.read(cx).snapshot(cx);
11420
11421        let mut edits = Vec::new();
11422        let mut unfold_ranges = Vec::new();
11423        let mut refold_creases = Vec::new();
11424
11425        let selections = self.selections.all::<Point>(cx);
11426        let mut selections = selections.iter().peekable();
11427        let mut contiguous_row_selections = Vec::new();
11428        let mut new_selections = Vec::new();
11429
11430        while let Some(selection) = selections.next() {
11431            // Find all the selections that span a contiguous row range
11432            let (start_row, end_row) = consume_contiguous_rows(
11433                &mut contiguous_row_selections,
11434                selection,
11435                &display_map,
11436                &mut selections,
11437            );
11438
11439            // Move the text spanned by the row range to be after the last line of the row range
11440            if end_row.0 <= buffer.max_point().row {
11441                let range_to_move =
11442                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11443                let insertion_point = display_map
11444                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11445                    .0;
11446
11447                // Don't move lines across excerpt boundaries
11448                if buffer
11449                    .excerpt_containing(range_to_move.start..insertion_point)
11450                    .is_some()
11451                {
11452                    let mut text = String::from("\n");
11453                    text.extend(buffer.text_for_range(range_to_move.clone()));
11454                    text.pop(); // Drop trailing newline
11455                    edits.push((
11456                        buffer.anchor_after(range_to_move.start)
11457                            ..buffer.anchor_before(range_to_move.end),
11458                        String::new(),
11459                    ));
11460                    let insertion_anchor = buffer.anchor_after(insertion_point);
11461                    edits.push((insertion_anchor..insertion_anchor, text));
11462
11463                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11464
11465                    // Move selections down
11466                    new_selections.extend(contiguous_row_selections.drain(..).map(
11467                        |mut selection| {
11468                            selection.start.row += row_delta;
11469                            selection.end.row += row_delta;
11470                            selection
11471                        },
11472                    ));
11473
11474                    // Move folds down
11475                    unfold_ranges.push(range_to_move.clone());
11476                    for fold in display_map.folds_in_range(
11477                        buffer.anchor_before(range_to_move.start)
11478                            ..buffer.anchor_after(range_to_move.end),
11479                    ) {
11480                        let mut start = fold.range.start.to_point(&buffer);
11481                        let mut end = fold.range.end.to_point(&buffer);
11482                        start.row += row_delta;
11483                        end.row += row_delta;
11484                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11485                    }
11486                }
11487            }
11488
11489            // If we didn't move line(s), preserve the existing selections
11490            new_selections.append(&mut contiguous_row_selections);
11491        }
11492
11493        self.transact(window, cx, |this, window, cx| {
11494            this.unfold_ranges(&unfold_ranges, true, true, cx);
11495            this.buffer.update(cx, |buffer, cx| {
11496                for (range, text) in edits {
11497                    buffer.edit([(range, text)], None, cx);
11498                }
11499            });
11500            this.fold_creases(refold_creases, true, window, cx);
11501            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11502        });
11503    }
11504
11505    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11506        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11507        let text_layout_details = &self.text_layout_details(window);
11508        self.transact(window, cx, |this, window, cx| {
11509            let edits = this.change_selections(Default::default(), window, cx, |s| {
11510                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11511                s.move_with(|display_map, selection| {
11512                    if !selection.is_empty() {
11513                        return;
11514                    }
11515
11516                    let mut head = selection.head();
11517                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11518                    if head.column() == display_map.line_len(head.row()) {
11519                        transpose_offset = display_map
11520                            .buffer_snapshot
11521                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11522                    }
11523
11524                    if transpose_offset == 0 {
11525                        return;
11526                    }
11527
11528                    *head.column_mut() += 1;
11529                    head = display_map.clip_point(head, Bias::Right);
11530                    let goal = SelectionGoal::HorizontalPosition(
11531                        display_map
11532                            .x_for_display_point(head, text_layout_details)
11533                            .into(),
11534                    );
11535                    selection.collapse_to(head, goal);
11536
11537                    let transpose_start = display_map
11538                        .buffer_snapshot
11539                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11540                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11541                        let transpose_end = display_map
11542                            .buffer_snapshot
11543                            .clip_offset(transpose_offset + 1, Bias::Right);
11544                        if let Some(ch) =
11545                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11546                        {
11547                            edits.push((transpose_start..transpose_offset, String::new()));
11548                            edits.push((transpose_end..transpose_end, ch.to_string()));
11549                        }
11550                    }
11551                });
11552                edits
11553            });
11554            this.buffer
11555                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11556            let selections = this.selections.all::<usize>(cx);
11557            this.change_selections(Default::default(), window, cx, |s| {
11558                s.select(selections);
11559            });
11560        });
11561    }
11562
11563    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11564        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11565        if self.mode.is_single_line() {
11566            cx.propagate();
11567            return;
11568        }
11569
11570        self.rewrap_impl(RewrapOptions::default(), cx)
11571    }
11572
11573    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11574        let buffer = self.buffer.read(cx).snapshot(cx);
11575        let selections = self.selections.all::<Point>(cx);
11576
11577        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11578        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11579            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11580                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11581                .peekable();
11582
11583            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11584                row
11585            } else {
11586                return Vec::new();
11587            };
11588
11589            let language_settings = buffer.language_settings_at(selection.head(), cx);
11590            let language_scope = buffer.language_scope_at(selection.head());
11591
11592            let indent_and_prefix_for_row =
11593                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11594                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11595                    let (comment_prefix, rewrap_prefix) =
11596                        if let Some(language_scope) = &language_scope {
11597                            let indent_end = Point::new(row, indent.len);
11598                            let comment_prefix = language_scope
11599                                .line_comment_prefixes()
11600                                .iter()
11601                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11602                                .map(|prefix| prefix.to_string());
11603                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11604                            let line_text_after_indent = buffer
11605                                .text_for_range(indent_end..line_end)
11606                                .collect::<String>();
11607                            let rewrap_prefix = language_scope
11608                                .rewrap_prefixes()
11609                                .iter()
11610                                .find_map(|prefix_regex| {
11611                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11612                                        if mat.start() == 0 {
11613                                            Some(mat.as_str().to_string())
11614                                        } else {
11615                                            None
11616                                        }
11617                                    })
11618                                })
11619                                .flatten();
11620                            (comment_prefix, rewrap_prefix)
11621                        } else {
11622                            (None, None)
11623                        };
11624                    (indent, comment_prefix, rewrap_prefix)
11625                };
11626
11627            let mut ranges = Vec::new();
11628            let from_empty_selection = selection.is_empty();
11629
11630            let mut current_range_start = first_row;
11631            let mut prev_row = first_row;
11632            let (
11633                mut current_range_indent,
11634                mut current_range_comment_prefix,
11635                mut current_range_rewrap_prefix,
11636            ) = indent_and_prefix_for_row(first_row);
11637
11638            for row in non_blank_rows_iter.skip(1) {
11639                let has_paragraph_break = row > prev_row + 1;
11640
11641                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11642                    indent_and_prefix_for_row(row);
11643
11644                let has_indent_change = row_indent != current_range_indent;
11645                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11646
11647                let has_boundary_change = has_comment_change
11648                    || row_rewrap_prefix.is_some()
11649                    || (has_indent_change && current_range_comment_prefix.is_some());
11650
11651                if has_paragraph_break || has_boundary_change {
11652                    ranges.push((
11653                        language_settings.clone(),
11654                        Point::new(current_range_start, 0)
11655                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11656                        current_range_indent,
11657                        current_range_comment_prefix.clone(),
11658                        current_range_rewrap_prefix.clone(),
11659                        from_empty_selection,
11660                    ));
11661                    current_range_start = row;
11662                    current_range_indent = row_indent;
11663                    current_range_comment_prefix = row_comment_prefix;
11664                    current_range_rewrap_prefix = row_rewrap_prefix;
11665                }
11666                prev_row = row;
11667            }
11668
11669            ranges.push((
11670                language_settings.clone(),
11671                Point::new(current_range_start, 0)
11672                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11673                current_range_indent,
11674                current_range_comment_prefix,
11675                current_range_rewrap_prefix,
11676                from_empty_selection,
11677            ));
11678
11679            ranges
11680        });
11681
11682        let mut edits = Vec::new();
11683        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11684
11685        for (
11686            language_settings,
11687            wrap_range,
11688            indent_size,
11689            comment_prefix,
11690            rewrap_prefix,
11691            from_empty_selection,
11692        ) in wrap_ranges
11693        {
11694            let mut start_row = wrap_range.start.row;
11695            let mut end_row = wrap_range.end.row;
11696
11697            // Skip selections that overlap with a range that has already been rewrapped.
11698            let selection_range = start_row..end_row;
11699            if rewrapped_row_ranges
11700                .iter()
11701                .any(|range| range.overlaps(&selection_range))
11702            {
11703                continue;
11704            }
11705
11706            let tab_size = language_settings.tab_size;
11707
11708            let indent_prefix = indent_size.chars().collect::<String>();
11709            let mut line_prefix = indent_prefix.clone();
11710            let mut inside_comment = false;
11711            if let Some(prefix) = &comment_prefix {
11712                line_prefix.push_str(prefix);
11713                inside_comment = true;
11714            }
11715            if let Some(prefix) = &rewrap_prefix {
11716                line_prefix.push_str(prefix);
11717            }
11718
11719            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11720                RewrapBehavior::InComments => inside_comment,
11721                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11722                RewrapBehavior::Anywhere => true,
11723            };
11724
11725            let should_rewrap = options.override_language_settings
11726                || allow_rewrap_based_on_language
11727                || self.hard_wrap.is_some();
11728            if !should_rewrap {
11729                continue;
11730            }
11731
11732            if from_empty_selection {
11733                'expand_upwards: while start_row > 0 {
11734                    let prev_row = start_row - 1;
11735                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11736                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11737                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11738                    {
11739                        start_row = prev_row;
11740                    } else {
11741                        break 'expand_upwards;
11742                    }
11743                }
11744
11745                'expand_downwards: while end_row < buffer.max_point().row {
11746                    let next_row = end_row + 1;
11747                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11748                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11749                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11750                    {
11751                        end_row = next_row;
11752                    } else {
11753                        break 'expand_downwards;
11754                    }
11755                }
11756            }
11757
11758            let start = Point::new(start_row, 0);
11759            let start_offset = start.to_offset(&buffer);
11760            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11761            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11762            let Some(lines_without_prefixes) = selection_text
11763                .lines()
11764                .enumerate()
11765                .map(|(ix, line)| {
11766                    let line_trimmed = line.trim_start();
11767                    if rewrap_prefix.is_some() && ix > 0 {
11768                        Ok(line_trimmed)
11769                    } else {
11770                        line_trimmed
11771                            .strip_prefix(&line_prefix.trim_start())
11772                            .with_context(|| {
11773                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11774                            })
11775                    }
11776                })
11777                .collect::<Result<Vec<_>, _>>()
11778                .log_err()
11779            else {
11780                continue;
11781            };
11782
11783            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11784                buffer
11785                    .language_settings_at(Point::new(start_row, 0), cx)
11786                    .preferred_line_length as usize
11787            });
11788
11789            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11790                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11791            } else {
11792                line_prefix.clone()
11793            };
11794
11795            let wrapped_text = wrap_with_prefix(
11796                line_prefix,
11797                subsequent_lines_prefix,
11798                lines_without_prefixes.join("\n"),
11799                wrap_column,
11800                tab_size,
11801                options.preserve_existing_whitespace,
11802            );
11803
11804            // TODO: should always use char-based diff while still supporting cursor behavior that
11805            // matches vim.
11806            let mut diff_options = DiffOptions::default();
11807            if options.override_language_settings {
11808                diff_options.max_word_diff_len = 0;
11809                diff_options.max_word_diff_line_count = 0;
11810            } else {
11811                diff_options.max_word_diff_len = usize::MAX;
11812                diff_options.max_word_diff_line_count = usize::MAX;
11813            }
11814
11815            for (old_range, new_text) in
11816                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11817            {
11818                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11819                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11820                edits.push((edit_start..edit_end, new_text));
11821            }
11822
11823            rewrapped_row_ranges.push(start_row..=end_row);
11824        }
11825
11826        self.buffer
11827            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11828    }
11829
11830    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11831        let mut text = String::new();
11832        let buffer = self.buffer.read(cx).snapshot(cx);
11833        let mut selections = self.selections.all::<Point>(cx);
11834        let mut clipboard_selections = Vec::with_capacity(selections.len());
11835        {
11836            let max_point = buffer.max_point();
11837            let mut is_first = true;
11838            for selection in &mut selections {
11839                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11840                if is_entire_line {
11841                    selection.start = Point::new(selection.start.row, 0);
11842                    if !selection.is_empty() && selection.end.column == 0 {
11843                        selection.end = cmp::min(max_point, selection.end);
11844                    } else {
11845                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11846                    }
11847                    selection.goal = SelectionGoal::None;
11848                }
11849                if is_first {
11850                    is_first = false;
11851                } else {
11852                    text += "\n";
11853                }
11854                let mut len = 0;
11855                for chunk in buffer.text_for_range(selection.start..selection.end) {
11856                    text.push_str(chunk);
11857                    len += chunk.len();
11858                }
11859                clipboard_selections.push(ClipboardSelection {
11860                    len,
11861                    is_entire_line,
11862                    first_line_indent: buffer
11863                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11864                        .len,
11865                });
11866            }
11867        }
11868
11869        self.transact(window, cx, |this, window, cx| {
11870            this.change_selections(Default::default(), window, cx, |s| {
11871                s.select(selections);
11872            });
11873            this.insert("", window, cx);
11874        });
11875        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11876    }
11877
11878    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11879        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11880        let item = self.cut_common(window, cx);
11881        cx.write_to_clipboard(item);
11882    }
11883
11884    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11885        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11886        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11887            s.move_with(|snapshot, sel| {
11888                if sel.is_empty() {
11889                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11890                }
11891            });
11892        });
11893        let item = self.cut_common(window, cx);
11894        cx.set_global(KillRing(item))
11895    }
11896
11897    pub fn kill_ring_yank(
11898        &mut self,
11899        _: &KillRingYank,
11900        window: &mut Window,
11901        cx: &mut Context<Self>,
11902    ) {
11903        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11904        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11905            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11906                (kill_ring.text().to_string(), kill_ring.metadata_json())
11907            } else {
11908                return;
11909            }
11910        } else {
11911            return;
11912        };
11913        self.do_paste(&text, metadata, false, window, cx);
11914    }
11915
11916    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11917        self.do_copy(true, cx);
11918    }
11919
11920    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11921        self.do_copy(false, cx);
11922    }
11923
11924    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11925        let selections = self.selections.all::<Point>(cx);
11926        let buffer = self.buffer.read(cx).read(cx);
11927        let mut text = String::new();
11928
11929        let mut clipboard_selections = Vec::with_capacity(selections.len());
11930        {
11931            let max_point = buffer.max_point();
11932            let mut is_first = true;
11933            for selection in &selections {
11934                let mut start = selection.start;
11935                let mut end = selection.end;
11936                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11937                if is_entire_line {
11938                    start = Point::new(start.row, 0);
11939                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11940                }
11941
11942                let mut trimmed_selections = Vec::new();
11943                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11944                    let row = MultiBufferRow(start.row);
11945                    let first_indent = buffer.indent_size_for_line(row);
11946                    if first_indent.len == 0 || start.column > first_indent.len {
11947                        trimmed_selections.push(start..end);
11948                    } else {
11949                        trimmed_selections.push(
11950                            Point::new(row.0, first_indent.len)
11951                                ..Point::new(row.0, buffer.line_len(row)),
11952                        );
11953                        for row in start.row + 1..=end.row {
11954                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11955                            if row == end.row {
11956                                line_len = end.column;
11957                            }
11958                            if line_len == 0 {
11959                                trimmed_selections
11960                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11961                                continue;
11962                            }
11963                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11964                            if row_indent_size.len >= first_indent.len {
11965                                trimmed_selections.push(
11966                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11967                                );
11968                            } else {
11969                                trimmed_selections.clear();
11970                                trimmed_selections.push(start..end);
11971                                break;
11972                            }
11973                        }
11974                    }
11975                } else {
11976                    trimmed_selections.push(start..end);
11977                }
11978
11979                for trimmed_range in trimmed_selections {
11980                    if is_first {
11981                        is_first = false;
11982                    } else {
11983                        text += "\n";
11984                    }
11985                    let mut len = 0;
11986                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11987                        text.push_str(chunk);
11988                        len += chunk.len();
11989                    }
11990                    clipboard_selections.push(ClipboardSelection {
11991                        len,
11992                        is_entire_line,
11993                        first_line_indent: buffer
11994                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11995                            .len,
11996                    });
11997                }
11998            }
11999        }
12000
12001        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12002            text,
12003            clipboard_selections,
12004        ));
12005    }
12006
12007    pub fn do_paste(
12008        &mut self,
12009        text: &String,
12010        clipboard_selections: Option<Vec<ClipboardSelection>>,
12011        handle_entire_lines: bool,
12012        window: &mut Window,
12013        cx: &mut Context<Self>,
12014    ) {
12015        if self.read_only(cx) {
12016            return;
12017        }
12018
12019        let clipboard_text = Cow::Borrowed(text);
12020
12021        self.transact(window, cx, |this, window, cx| {
12022            if let Some(mut clipboard_selections) = clipboard_selections {
12023                let old_selections = this.selections.all::<usize>(cx);
12024                let all_selections_were_entire_line =
12025                    clipboard_selections.iter().all(|s| s.is_entire_line);
12026                let first_selection_indent_column =
12027                    clipboard_selections.first().map(|s| s.first_line_indent);
12028                if clipboard_selections.len() != old_selections.len() {
12029                    clipboard_selections.drain(..);
12030                }
12031                let cursor_offset = this.selections.last::<usize>(cx).head();
12032                let mut auto_indent_on_paste = true;
12033
12034                this.buffer.update(cx, |buffer, cx| {
12035                    let snapshot = buffer.read(cx);
12036                    auto_indent_on_paste = snapshot
12037                        .language_settings_at(cursor_offset, cx)
12038                        .auto_indent_on_paste;
12039
12040                    let mut start_offset = 0;
12041                    let mut edits = Vec::new();
12042                    let mut original_indent_columns = Vec::new();
12043                    for (ix, selection) in old_selections.iter().enumerate() {
12044                        let to_insert;
12045                        let entire_line;
12046                        let original_indent_column;
12047                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12048                            let end_offset = start_offset + clipboard_selection.len;
12049                            to_insert = &clipboard_text[start_offset..end_offset];
12050                            entire_line = clipboard_selection.is_entire_line;
12051                            start_offset = end_offset + 1;
12052                            original_indent_column = Some(clipboard_selection.first_line_indent);
12053                        } else {
12054                            to_insert = clipboard_text.as_str();
12055                            entire_line = all_selections_were_entire_line;
12056                            original_indent_column = first_selection_indent_column
12057                        }
12058
12059                        // If the corresponding selection was empty when this slice of the
12060                        // clipboard text was written, then the entire line containing the
12061                        // selection was copied. If this selection is also currently empty,
12062                        // then paste the line before the current line of the buffer.
12063                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12064                            let column = selection.start.to_point(&snapshot).column as usize;
12065                            let line_start = selection.start - column;
12066                            line_start..line_start
12067                        } else {
12068                            selection.range()
12069                        };
12070
12071                        edits.push((range, to_insert));
12072                        original_indent_columns.push(original_indent_column);
12073                    }
12074                    drop(snapshot);
12075
12076                    buffer.edit(
12077                        edits,
12078                        if auto_indent_on_paste {
12079                            Some(AutoindentMode::Block {
12080                                original_indent_columns,
12081                            })
12082                        } else {
12083                            None
12084                        },
12085                        cx,
12086                    );
12087                });
12088
12089                let selections = this.selections.all::<usize>(cx);
12090                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12091            } else {
12092                this.insert(&clipboard_text, window, cx);
12093            }
12094        });
12095    }
12096
12097    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12098        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12099        if let Some(item) = cx.read_from_clipboard() {
12100            let entries = item.entries();
12101
12102            match entries.first() {
12103                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12104                // of all the pasted entries.
12105                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12106                    .do_paste(
12107                        clipboard_string.text(),
12108                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12109                        true,
12110                        window,
12111                        cx,
12112                    ),
12113                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12114            }
12115        }
12116    }
12117
12118    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12119        if self.read_only(cx) {
12120            return;
12121        }
12122
12123        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12124
12125        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12126            if let Some((selections, _)) =
12127                self.selection_history.transaction(transaction_id).cloned()
12128            {
12129                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12130                    s.select_anchors(selections.to_vec());
12131                });
12132            } else {
12133                log::error!(
12134                    "No entry in selection_history found for undo. \
12135                     This may correspond to a bug where undo does not update the selection. \
12136                     If this is occurring, please add details to \
12137                     https://github.com/zed-industries/zed/issues/22692"
12138                );
12139            }
12140            self.request_autoscroll(Autoscroll::fit(), cx);
12141            self.unmark_text(window, cx);
12142            self.refresh_inline_completion(true, false, window, cx);
12143            cx.emit(EditorEvent::Edited { transaction_id });
12144            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12145        }
12146    }
12147
12148    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12149        if self.read_only(cx) {
12150            return;
12151        }
12152
12153        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12154
12155        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12156            if let Some((_, Some(selections))) =
12157                self.selection_history.transaction(transaction_id).cloned()
12158            {
12159                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12160                    s.select_anchors(selections.to_vec());
12161                });
12162            } else {
12163                log::error!(
12164                    "No entry in selection_history found for redo. \
12165                     This may correspond to a bug where undo does not update the selection. \
12166                     If this is occurring, please add details to \
12167                     https://github.com/zed-industries/zed/issues/22692"
12168                );
12169            }
12170            self.request_autoscroll(Autoscroll::fit(), cx);
12171            self.unmark_text(window, cx);
12172            self.refresh_inline_completion(true, false, window, cx);
12173            cx.emit(EditorEvent::Edited { transaction_id });
12174        }
12175    }
12176
12177    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12178        self.buffer
12179            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12180    }
12181
12182    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12183        self.buffer
12184            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12185    }
12186
12187    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12189        self.change_selections(Default::default(), window, cx, |s| {
12190            s.move_with(|map, selection| {
12191                let cursor = if selection.is_empty() {
12192                    movement::left(map, selection.start)
12193                } else {
12194                    selection.start
12195                };
12196                selection.collapse_to(cursor, SelectionGoal::None);
12197            });
12198        })
12199    }
12200
12201    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12203        self.change_selections(Default::default(), window, cx, |s| {
12204            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12205        })
12206    }
12207
12208    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12209        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12210        self.change_selections(Default::default(), window, cx, |s| {
12211            s.move_with(|map, selection| {
12212                let cursor = if selection.is_empty() {
12213                    movement::right(map, selection.end)
12214                } else {
12215                    selection.end
12216                };
12217                selection.collapse_to(cursor, SelectionGoal::None)
12218            });
12219        })
12220    }
12221
12222    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12223        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12224        self.change_selections(Default::default(), window, cx, |s| {
12225            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12226        })
12227    }
12228
12229    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12230        if self.take_rename(true, window, cx).is_some() {
12231            return;
12232        }
12233
12234        if self.mode.is_single_line() {
12235            cx.propagate();
12236            return;
12237        }
12238
12239        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12240
12241        let text_layout_details = &self.text_layout_details(window);
12242        let selection_count = self.selections.count();
12243        let first_selection = self.selections.first_anchor();
12244
12245        self.change_selections(Default::default(), window, cx, |s| {
12246            s.move_with(|map, selection| {
12247                if !selection.is_empty() {
12248                    selection.goal = SelectionGoal::None;
12249                }
12250                let (cursor, goal) = movement::up(
12251                    map,
12252                    selection.start,
12253                    selection.goal,
12254                    false,
12255                    text_layout_details,
12256                );
12257                selection.collapse_to(cursor, goal);
12258            });
12259        });
12260
12261        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12262        {
12263            cx.propagate();
12264        }
12265    }
12266
12267    pub fn move_up_by_lines(
12268        &mut self,
12269        action: &MoveUpByLines,
12270        window: &mut Window,
12271        cx: &mut Context<Self>,
12272    ) {
12273        if self.take_rename(true, window, cx).is_some() {
12274            return;
12275        }
12276
12277        if self.mode.is_single_line() {
12278            cx.propagate();
12279            return;
12280        }
12281
12282        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12283
12284        let text_layout_details = &self.text_layout_details(window);
12285
12286        self.change_selections(Default::default(), window, cx, |s| {
12287            s.move_with(|map, selection| {
12288                if !selection.is_empty() {
12289                    selection.goal = SelectionGoal::None;
12290                }
12291                let (cursor, goal) = movement::up_by_rows(
12292                    map,
12293                    selection.start,
12294                    action.lines,
12295                    selection.goal,
12296                    false,
12297                    text_layout_details,
12298                );
12299                selection.collapse_to(cursor, goal);
12300            });
12301        })
12302    }
12303
12304    pub fn move_down_by_lines(
12305        &mut self,
12306        action: &MoveDownByLines,
12307        window: &mut Window,
12308        cx: &mut Context<Self>,
12309    ) {
12310        if self.take_rename(true, window, cx).is_some() {
12311            return;
12312        }
12313
12314        if self.mode.is_single_line() {
12315            cx.propagate();
12316            return;
12317        }
12318
12319        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12320
12321        let text_layout_details = &self.text_layout_details(window);
12322
12323        self.change_selections(Default::default(), window, cx, |s| {
12324            s.move_with(|map, selection| {
12325                if !selection.is_empty() {
12326                    selection.goal = SelectionGoal::None;
12327                }
12328                let (cursor, goal) = movement::down_by_rows(
12329                    map,
12330                    selection.start,
12331                    action.lines,
12332                    selection.goal,
12333                    false,
12334                    text_layout_details,
12335                );
12336                selection.collapse_to(cursor, goal);
12337            });
12338        })
12339    }
12340
12341    pub fn select_down_by_lines(
12342        &mut self,
12343        action: &SelectDownByLines,
12344        window: &mut Window,
12345        cx: &mut Context<Self>,
12346    ) {
12347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12348        let text_layout_details = &self.text_layout_details(window);
12349        self.change_selections(Default::default(), window, cx, |s| {
12350            s.move_heads_with(|map, head, goal| {
12351                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12352            })
12353        })
12354    }
12355
12356    pub fn select_up_by_lines(
12357        &mut self,
12358        action: &SelectUpByLines,
12359        window: &mut Window,
12360        cx: &mut Context<Self>,
12361    ) {
12362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12363        let text_layout_details = &self.text_layout_details(window);
12364        self.change_selections(Default::default(), window, cx, |s| {
12365            s.move_heads_with(|map, head, goal| {
12366                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12367            })
12368        })
12369    }
12370
12371    pub fn select_page_up(
12372        &mut self,
12373        _: &SelectPageUp,
12374        window: &mut Window,
12375        cx: &mut Context<Self>,
12376    ) {
12377        let Some(row_count) = self.visible_row_count() else {
12378            return;
12379        };
12380
12381        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12382
12383        let text_layout_details = &self.text_layout_details(window);
12384
12385        self.change_selections(Default::default(), window, cx, |s| {
12386            s.move_heads_with(|map, head, goal| {
12387                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12388            })
12389        })
12390    }
12391
12392    pub fn move_page_up(
12393        &mut self,
12394        action: &MovePageUp,
12395        window: &mut Window,
12396        cx: &mut Context<Self>,
12397    ) {
12398        if self.take_rename(true, window, cx).is_some() {
12399            return;
12400        }
12401
12402        if self
12403            .context_menu
12404            .borrow_mut()
12405            .as_mut()
12406            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12407            .unwrap_or(false)
12408        {
12409            return;
12410        }
12411
12412        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12413            cx.propagate();
12414            return;
12415        }
12416
12417        let Some(row_count) = self.visible_row_count() else {
12418            return;
12419        };
12420
12421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12422
12423        let effects = if action.center_cursor {
12424            SelectionEffects::scroll(Autoscroll::center())
12425        } else {
12426            SelectionEffects::default()
12427        };
12428
12429        let text_layout_details = &self.text_layout_details(window);
12430
12431        self.change_selections(effects, window, cx, |s| {
12432            s.move_with(|map, selection| {
12433                if !selection.is_empty() {
12434                    selection.goal = SelectionGoal::None;
12435                }
12436                let (cursor, goal) = movement::up_by_rows(
12437                    map,
12438                    selection.end,
12439                    row_count,
12440                    selection.goal,
12441                    false,
12442                    text_layout_details,
12443                );
12444                selection.collapse_to(cursor, goal);
12445            });
12446        });
12447    }
12448
12449    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12450        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12451        let text_layout_details = &self.text_layout_details(window);
12452        self.change_selections(Default::default(), window, cx, |s| {
12453            s.move_heads_with(|map, head, goal| {
12454                movement::up(map, head, goal, false, text_layout_details)
12455            })
12456        })
12457    }
12458
12459    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12460        self.take_rename(true, window, cx);
12461
12462        if self.mode.is_single_line() {
12463            cx.propagate();
12464            return;
12465        }
12466
12467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12468
12469        let text_layout_details = &self.text_layout_details(window);
12470        let selection_count = self.selections.count();
12471        let first_selection = self.selections.first_anchor();
12472
12473        self.change_selections(Default::default(), window, cx, |s| {
12474            s.move_with(|map, selection| {
12475                if !selection.is_empty() {
12476                    selection.goal = SelectionGoal::None;
12477                }
12478                let (cursor, goal) = movement::down(
12479                    map,
12480                    selection.end,
12481                    selection.goal,
12482                    false,
12483                    text_layout_details,
12484                );
12485                selection.collapse_to(cursor, goal);
12486            });
12487        });
12488
12489        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12490        {
12491            cx.propagate();
12492        }
12493    }
12494
12495    pub fn select_page_down(
12496        &mut self,
12497        _: &SelectPageDown,
12498        window: &mut Window,
12499        cx: &mut Context<Self>,
12500    ) {
12501        let Some(row_count) = self.visible_row_count() else {
12502            return;
12503        };
12504
12505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12506
12507        let text_layout_details = &self.text_layout_details(window);
12508
12509        self.change_selections(Default::default(), window, cx, |s| {
12510            s.move_heads_with(|map, head, goal| {
12511                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12512            })
12513        })
12514    }
12515
12516    pub fn move_page_down(
12517        &mut self,
12518        action: &MovePageDown,
12519        window: &mut Window,
12520        cx: &mut Context<Self>,
12521    ) {
12522        if self.take_rename(true, window, cx).is_some() {
12523            return;
12524        }
12525
12526        if self
12527            .context_menu
12528            .borrow_mut()
12529            .as_mut()
12530            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12531            .unwrap_or(false)
12532        {
12533            return;
12534        }
12535
12536        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12537            cx.propagate();
12538            return;
12539        }
12540
12541        let Some(row_count) = self.visible_row_count() else {
12542            return;
12543        };
12544
12545        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12546
12547        let effects = if action.center_cursor {
12548            SelectionEffects::scroll(Autoscroll::center())
12549        } else {
12550            SelectionEffects::default()
12551        };
12552
12553        let text_layout_details = &self.text_layout_details(window);
12554        self.change_selections(effects, window, cx, |s| {
12555            s.move_with(|map, selection| {
12556                if !selection.is_empty() {
12557                    selection.goal = SelectionGoal::None;
12558                }
12559                let (cursor, goal) = movement::down_by_rows(
12560                    map,
12561                    selection.end,
12562                    row_count,
12563                    selection.goal,
12564                    false,
12565                    text_layout_details,
12566                );
12567                selection.collapse_to(cursor, goal);
12568            });
12569        });
12570    }
12571
12572    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12573        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12574        let text_layout_details = &self.text_layout_details(window);
12575        self.change_selections(Default::default(), window, cx, |s| {
12576            s.move_heads_with(|map, head, goal| {
12577                movement::down(map, head, goal, false, text_layout_details)
12578            })
12579        });
12580    }
12581
12582    pub fn context_menu_first(
12583        &mut self,
12584        _: &ContextMenuFirst,
12585        window: &mut Window,
12586        cx: &mut Context<Self>,
12587    ) {
12588        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12589            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12590        }
12591    }
12592
12593    pub fn context_menu_prev(
12594        &mut self,
12595        _: &ContextMenuPrevious,
12596        window: &mut Window,
12597        cx: &mut Context<Self>,
12598    ) {
12599        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12600            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12601        }
12602    }
12603
12604    pub fn context_menu_next(
12605        &mut self,
12606        _: &ContextMenuNext,
12607        window: &mut Window,
12608        cx: &mut Context<Self>,
12609    ) {
12610        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12611            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12612        }
12613    }
12614
12615    pub fn context_menu_last(
12616        &mut self,
12617        _: &ContextMenuLast,
12618        window: &mut Window,
12619        cx: &mut Context<Self>,
12620    ) {
12621        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12622            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12623        }
12624    }
12625
12626    pub fn signature_help_prev(
12627        &mut self,
12628        _: &SignatureHelpPrevious,
12629        _: &mut Window,
12630        cx: &mut Context<Self>,
12631    ) {
12632        if let Some(popover) = self.signature_help_state.popover_mut() {
12633            if popover.current_signature == 0 {
12634                popover.current_signature = popover.signatures.len() - 1;
12635            } else {
12636                popover.current_signature -= 1;
12637            }
12638            cx.notify();
12639        }
12640    }
12641
12642    pub fn signature_help_next(
12643        &mut self,
12644        _: &SignatureHelpNext,
12645        _: &mut Window,
12646        cx: &mut Context<Self>,
12647    ) {
12648        if let Some(popover) = self.signature_help_state.popover_mut() {
12649            if popover.current_signature + 1 == popover.signatures.len() {
12650                popover.current_signature = 0;
12651            } else {
12652                popover.current_signature += 1;
12653            }
12654            cx.notify();
12655        }
12656    }
12657
12658    pub fn move_to_previous_word_start(
12659        &mut self,
12660        _: &MoveToPreviousWordStart,
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                (
12668                    movement::previous_word_start(map, head),
12669                    SelectionGoal::None,
12670                )
12671            });
12672        })
12673    }
12674
12675    pub fn move_to_previous_subword_start(
12676        &mut self,
12677        _: &MoveToPreviousSubwordStart,
12678        window: &mut Window,
12679        cx: &mut Context<Self>,
12680    ) {
12681        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12682        self.change_selections(Default::default(), window, cx, |s| {
12683            s.move_cursors_with(|map, head, _| {
12684                (
12685                    movement::previous_subword_start(map, head),
12686                    SelectionGoal::None,
12687                )
12688            });
12689        })
12690    }
12691
12692    pub fn select_to_previous_word_start(
12693        &mut self,
12694        _: &SelectToPreviousWordStart,
12695        window: &mut Window,
12696        cx: &mut Context<Self>,
12697    ) {
12698        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12699        self.change_selections(Default::default(), window, cx, |s| {
12700            s.move_heads_with(|map, head, _| {
12701                (
12702                    movement::previous_word_start(map, head),
12703                    SelectionGoal::None,
12704                )
12705            });
12706        })
12707    }
12708
12709    pub fn select_to_previous_subword_start(
12710        &mut self,
12711        _: &SelectToPreviousSubwordStart,
12712        window: &mut Window,
12713        cx: &mut Context<Self>,
12714    ) {
12715        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12716        self.change_selections(Default::default(), window, cx, |s| {
12717            s.move_heads_with(|map, head, _| {
12718                (
12719                    movement::previous_subword_start(map, head),
12720                    SelectionGoal::None,
12721                )
12722            });
12723        })
12724    }
12725
12726    pub fn delete_to_previous_word_start(
12727        &mut self,
12728        action: &DeleteToPreviousWordStart,
12729        window: &mut Window,
12730        cx: &mut Context<Self>,
12731    ) {
12732        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12733        self.transact(window, cx, |this, window, cx| {
12734            this.select_autoclose_pair(window, cx);
12735            this.change_selections(Default::default(), window, cx, |s| {
12736                s.move_with(|map, selection| {
12737                    if selection.is_empty() {
12738                        let cursor = if action.ignore_newlines {
12739                            movement::previous_word_start(map, selection.head())
12740                        } else {
12741                            movement::previous_word_start_or_newline(map, selection.head())
12742                        };
12743                        selection.set_head(cursor, SelectionGoal::None);
12744                    }
12745                });
12746            });
12747            this.insert("", window, cx);
12748        });
12749    }
12750
12751    pub fn delete_to_previous_subword_start(
12752        &mut self,
12753        _: &DeleteToPreviousSubwordStart,
12754        window: &mut Window,
12755        cx: &mut Context<Self>,
12756    ) {
12757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12758        self.transact(window, cx, |this, window, cx| {
12759            this.select_autoclose_pair(window, cx);
12760            this.change_selections(Default::default(), window, cx, |s| {
12761                s.move_with(|map, selection| {
12762                    if selection.is_empty() {
12763                        let cursor = movement::previous_subword_start(map, selection.head());
12764                        selection.set_head(cursor, SelectionGoal::None);
12765                    }
12766                });
12767            });
12768            this.insert("", window, cx);
12769        });
12770    }
12771
12772    pub fn move_to_next_word_end(
12773        &mut self,
12774        _: &MoveToNextWordEnd,
12775        window: &mut Window,
12776        cx: &mut Context<Self>,
12777    ) {
12778        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12779        self.change_selections(Default::default(), window, cx, |s| {
12780            s.move_cursors_with(|map, head, _| {
12781                (movement::next_word_end(map, head), SelectionGoal::None)
12782            });
12783        })
12784    }
12785
12786    pub fn move_to_next_subword_end(
12787        &mut self,
12788        _: &MoveToNextSubwordEnd,
12789        window: &mut Window,
12790        cx: &mut Context<Self>,
12791    ) {
12792        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12793        self.change_selections(Default::default(), window, cx, |s| {
12794            s.move_cursors_with(|map, head, _| {
12795                (movement::next_subword_end(map, head), SelectionGoal::None)
12796            });
12797        })
12798    }
12799
12800    pub fn select_to_next_word_end(
12801        &mut self,
12802        _: &SelectToNextWordEnd,
12803        window: &mut Window,
12804        cx: &mut Context<Self>,
12805    ) {
12806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12807        self.change_selections(Default::default(), window, cx, |s| {
12808            s.move_heads_with(|map, head, _| {
12809                (movement::next_word_end(map, head), SelectionGoal::None)
12810            });
12811        })
12812    }
12813
12814    pub fn select_to_next_subword_end(
12815        &mut self,
12816        _: &SelectToNextSubwordEnd,
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_heads_with(|map, head, _| {
12823                (movement::next_subword_end(map, head), SelectionGoal::None)
12824            });
12825        })
12826    }
12827
12828    pub fn delete_to_next_word_end(
12829        &mut self,
12830        action: &DeleteToNextWordEnd,
12831        window: &mut Window,
12832        cx: &mut Context<Self>,
12833    ) {
12834        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12835        self.transact(window, cx, |this, window, cx| {
12836            this.change_selections(Default::default(), window, cx, |s| {
12837                s.move_with(|map, selection| {
12838                    if selection.is_empty() {
12839                        let cursor = if action.ignore_newlines {
12840                            movement::next_word_end(map, selection.head())
12841                        } else {
12842                            movement::next_word_end_or_newline(map, selection.head())
12843                        };
12844                        selection.set_head(cursor, SelectionGoal::None);
12845                    }
12846                });
12847            });
12848            this.insert("", window, cx);
12849        });
12850    }
12851
12852    pub fn delete_to_next_subword_end(
12853        &mut self,
12854        _: &DeleteToNextSubwordEnd,
12855        window: &mut Window,
12856        cx: &mut Context<Self>,
12857    ) {
12858        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12859        self.transact(window, cx, |this, window, cx| {
12860            this.change_selections(Default::default(), window, cx, |s| {
12861                s.move_with(|map, selection| {
12862                    if selection.is_empty() {
12863                        let cursor = movement::next_subword_end(map, selection.head());
12864                        selection.set_head(cursor, SelectionGoal::None);
12865                    }
12866                });
12867            });
12868            this.insert("", window, cx);
12869        });
12870    }
12871
12872    pub fn move_to_beginning_of_line(
12873        &mut self,
12874        action: &MoveToBeginningOfLine,
12875        window: &mut Window,
12876        cx: &mut Context<Self>,
12877    ) {
12878        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12879        self.change_selections(Default::default(), window, cx, |s| {
12880            s.move_cursors_with(|map, head, _| {
12881                (
12882                    movement::indented_line_beginning(
12883                        map,
12884                        head,
12885                        action.stop_at_soft_wraps,
12886                        action.stop_at_indent,
12887                    ),
12888                    SelectionGoal::None,
12889                )
12890            });
12891        })
12892    }
12893
12894    pub fn select_to_beginning_of_line(
12895        &mut self,
12896        action: &SelectToBeginningOfLine,
12897        window: &mut Window,
12898        cx: &mut Context<Self>,
12899    ) {
12900        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12901        self.change_selections(Default::default(), window, cx, |s| {
12902            s.move_heads_with(|map, head, _| {
12903                (
12904                    movement::indented_line_beginning(
12905                        map,
12906                        head,
12907                        action.stop_at_soft_wraps,
12908                        action.stop_at_indent,
12909                    ),
12910                    SelectionGoal::None,
12911                )
12912            });
12913        });
12914    }
12915
12916    pub fn delete_to_beginning_of_line(
12917        &mut self,
12918        action: &DeleteToBeginningOfLine,
12919        window: &mut Window,
12920        cx: &mut Context<Self>,
12921    ) {
12922        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12923        self.transact(window, cx, |this, window, cx| {
12924            this.change_selections(Default::default(), window, cx, |s| {
12925                s.move_with(|_, selection| {
12926                    selection.reversed = true;
12927                });
12928            });
12929
12930            this.select_to_beginning_of_line(
12931                &SelectToBeginningOfLine {
12932                    stop_at_soft_wraps: false,
12933                    stop_at_indent: action.stop_at_indent,
12934                },
12935                window,
12936                cx,
12937            );
12938            this.backspace(&Backspace, window, cx);
12939        });
12940    }
12941
12942    pub fn move_to_end_of_line(
12943        &mut self,
12944        action: &MoveToEndOfLine,
12945        window: &mut Window,
12946        cx: &mut Context<Self>,
12947    ) {
12948        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12949        self.change_selections(Default::default(), window, cx, |s| {
12950            s.move_cursors_with(|map, head, _| {
12951                (
12952                    movement::line_end(map, head, action.stop_at_soft_wraps),
12953                    SelectionGoal::None,
12954                )
12955            });
12956        })
12957    }
12958
12959    pub fn select_to_end_of_line(
12960        &mut self,
12961        action: &SelectToEndOfLine,
12962        window: &mut Window,
12963        cx: &mut Context<Self>,
12964    ) {
12965        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12966        self.change_selections(Default::default(), window, cx, |s| {
12967            s.move_heads_with(|map, head, _| {
12968                (
12969                    movement::line_end(map, head, action.stop_at_soft_wraps),
12970                    SelectionGoal::None,
12971                )
12972            });
12973        })
12974    }
12975
12976    pub fn delete_to_end_of_line(
12977        &mut self,
12978        _: &DeleteToEndOfLine,
12979        window: &mut Window,
12980        cx: &mut Context<Self>,
12981    ) {
12982        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12983        self.transact(window, cx, |this, window, cx| {
12984            this.select_to_end_of_line(
12985                &SelectToEndOfLine {
12986                    stop_at_soft_wraps: false,
12987                },
12988                window,
12989                cx,
12990            );
12991            this.delete(&Delete, window, cx);
12992        });
12993    }
12994
12995    pub fn cut_to_end_of_line(
12996        &mut self,
12997        _: &CutToEndOfLine,
12998        window: &mut Window,
12999        cx: &mut Context<Self>,
13000    ) {
13001        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13002        self.transact(window, cx, |this, window, cx| {
13003            this.select_to_end_of_line(
13004                &SelectToEndOfLine {
13005                    stop_at_soft_wraps: false,
13006                },
13007                window,
13008                cx,
13009            );
13010            this.cut(&Cut, window, cx);
13011        });
13012    }
13013
13014    pub fn move_to_start_of_paragraph(
13015        &mut self,
13016        _: &MoveToStartOfParagraph,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) {
13020        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13021            cx.propagate();
13022            return;
13023        }
13024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13025        self.change_selections(Default::default(), window, cx, |s| {
13026            s.move_with(|map, selection| {
13027                selection.collapse_to(
13028                    movement::start_of_paragraph(map, selection.head(), 1),
13029                    SelectionGoal::None,
13030                )
13031            });
13032        })
13033    }
13034
13035    pub fn move_to_end_of_paragraph(
13036        &mut self,
13037        _: &MoveToEndOfParagraph,
13038        window: &mut Window,
13039        cx: &mut Context<Self>,
13040    ) {
13041        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13042            cx.propagate();
13043            return;
13044        }
13045        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13046        self.change_selections(Default::default(), window, cx, |s| {
13047            s.move_with(|map, selection| {
13048                selection.collapse_to(
13049                    movement::end_of_paragraph(map, selection.head(), 1),
13050                    SelectionGoal::None,
13051                )
13052            });
13053        })
13054    }
13055
13056    pub fn select_to_start_of_paragraph(
13057        &mut self,
13058        _: &SelectToStartOfParagraph,
13059        window: &mut Window,
13060        cx: &mut Context<Self>,
13061    ) {
13062        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13063            cx.propagate();
13064            return;
13065        }
13066        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13067        self.change_selections(Default::default(), window, cx, |s| {
13068            s.move_heads_with(|map, head, _| {
13069                (
13070                    movement::start_of_paragraph(map, head, 1),
13071                    SelectionGoal::None,
13072                )
13073            });
13074        })
13075    }
13076
13077    pub fn select_to_end_of_paragraph(
13078        &mut self,
13079        _: &SelectToEndOfParagraph,
13080        window: &mut Window,
13081        cx: &mut Context<Self>,
13082    ) {
13083        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13084            cx.propagate();
13085            return;
13086        }
13087        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13088        self.change_selections(Default::default(), window, cx, |s| {
13089            s.move_heads_with(|map, head, _| {
13090                (
13091                    movement::end_of_paragraph(map, head, 1),
13092                    SelectionGoal::None,
13093                )
13094            });
13095        })
13096    }
13097
13098    pub fn move_to_start_of_excerpt(
13099        &mut self,
13100        _: &MoveToStartOfExcerpt,
13101        window: &mut Window,
13102        cx: &mut Context<Self>,
13103    ) {
13104        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13105            cx.propagate();
13106            return;
13107        }
13108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13109        self.change_selections(Default::default(), window, cx, |s| {
13110            s.move_with(|map, selection| {
13111                selection.collapse_to(
13112                    movement::start_of_excerpt(
13113                        map,
13114                        selection.head(),
13115                        workspace::searchable::Direction::Prev,
13116                    ),
13117                    SelectionGoal::None,
13118                )
13119            });
13120        })
13121    }
13122
13123    pub fn move_to_start_of_next_excerpt(
13124        &mut self,
13125        _: &MoveToStartOfNextExcerpt,
13126        window: &mut Window,
13127        cx: &mut Context<Self>,
13128    ) {
13129        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13130            cx.propagate();
13131            return;
13132        }
13133
13134        self.change_selections(Default::default(), window, cx, |s| {
13135            s.move_with(|map, selection| {
13136                selection.collapse_to(
13137                    movement::start_of_excerpt(
13138                        map,
13139                        selection.head(),
13140                        workspace::searchable::Direction::Next,
13141                    ),
13142                    SelectionGoal::None,
13143                )
13144            });
13145        })
13146    }
13147
13148    pub fn move_to_end_of_excerpt(
13149        &mut self,
13150        _: &MoveToEndOfExcerpt,
13151        window: &mut Window,
13152        cx: &mut Context<Self>,
13153    ) {
13154        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13155            cx.propagate();
13156            return;
13157        }
13158        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13159        self.change_selections(Default::default(), window, cx, |s| {
13160            s.move_with(|map, selection| {
13161                selection.collapse_to(
13162                    movement::end_of_excerpt(
13163                        map,
13164                        selection.head(),
13165                        workspace::searchable::Direction::Next,
13166                    ),
13167                    SelectionGoal::None,
13168                )
13169            });
13170        })
13171    }
13172
13173    pub fn move_to_end_of_previous_excerpt(
13174        &mut self,
13175        _: &MoveToEndOfPreviousExcerpt,
13176        window: &mut Window,
13177        cx: &mut Context<Self>,
13178    ) {
13179        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13180            cx.propagate();
13181            return;
13182        }
13183        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13184        self.change_selections(Default::default(), window, cx, |s| {
13185            s.move_with(|map, selection| {
13186                selection.collapse_to(
13187                    movement::end_of_excerpt(
13188                        map,
13189                        selection.head(),
13190                        workspace::searchable::Direction::Prev,
13191                    ),
13192                    SelectionGoal::None,
13193                )
13194            });
13195        })
13196    }
13197
13198    pub fn select_to_start_of_excerpt(
13199        &mut self,
13200        _: &SelectToStartOfExcerpt,
13201        window: &mut Window,
13202        cx: &mut Context<Self>,
13203    ) {
13204        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13205            cx.propagate();
13206            return;
13207        }
13208        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13209        self.change_selections(Default::default(), window, cx, |s| {
13210            s.move_heads_with(|map, head, _| {
13211                (
13212                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13213                    SelectionGoal::None,
13214                )
13215            });
13216        })
13217    }
13218
13219    pub fn select_to_start_of_next_excerpt(
13220        &mut self,
13221        _: &SelectToStartOfNextExcerpt,
13222        window: &mut Window,
13223        cx: &mut Context<Self>,
13224    ) {
13225        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13226            cx.propagate();
13227            return;
13228        }
13229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13230        self.change_selections(Default::default(), window, cx, |s| {
13231            s.move_heads_with(|map, head, _| {
13232                (
13233                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13234                    SelectionGoal::None,
13235                )
13236            });
13237        })
13238    }
13239
13240    pub fn select_to_end_of_excerpt(
13241        &mut self,
13242        _: &SelectToEndOfExcerpt,
13243        window: &mut Window,
13244        cx: &mut Context<Self>,
13245    ) {
13246        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13247            cx.propagate();
13248            return;
13249        }
13250        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13251        self.change_selections(Default::default(), window, cx, |s| {
13252            s.move_heads_with(|map, head, _| {
13253                (
13254                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13255                    SelectionGoal::None,
13256                )
13257            });
13258        })
13259    }
13260
13261    pub fn select_to_end_of_previous_excerpt(
13262        &mut self,
13263        _: &SelectToEndOfPreviousExcerpt,
13264        window: &mut Window,
13265        cx: &mut Context<Self>,
13266    ) {
13267        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13268            cx.propagate();
13269            return;
13270        }
13271        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13272        self.change_selections(Default::default(), window, cx, |s| {
13273            s.move_heads_with(|map, head, _| {
13274                (
13275                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13276                    SelectionGoal::None,
13277                )
13278            });
13279        })
13280    }
13281
13282    pub fn move_to_beginning(
13283        &mut self,
13284        _: &MoveToBeginning,
13285        window: &mut Window,
13286        cx: &mut Context<Self>,
13287    ) {
13288        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13289            cx.propagate();
13290            return;
13291        }
13292        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13293        self.change_selections(Default::default(), window, cx, |s| {
13294            s.select_ranges(vec![0..0]);
13295        });
13296    }
13297
13298    pub fn select_to_beginning(
13299        &mut self,
13300        _: &SelectToBeginning,
13301        window: &mut Window,
13302        cx: &mut Context<Self>,
13303    ) {
13304        let mut selection = self.selections.last::<Point>(cx);
13305        selection.set_head(Point::zero(), SelectionGoal::None);
13306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13307        self.change_selections(Default::default(), window, cx, |s| {
13308            s.select(vec![selection]);
13309        });
13310    }
13311
13312    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13313        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13314            cx.propagate();
13315            return;
13316        }
13317        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13318        let cursor = self.buffer.read(cx).read(cx).len();
13319        self.change_selections(Default::default(), window, cx, |s| {
13320            s.select_ranges(vec![cursor..cursor])
13321        });
13322    }
13323
13324    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13325        self.nav_history = nav_history;
13326    }
13327
13328    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13329        self.nav_history.as_ref()
13330    }
13331
13332    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13333        self.push_to_nav_history(
13334            self.selections.newest_anchor().head(),
13335            None,
13336            false,
13337            true,
13338            cx,
13339        );
13340    }
13341
13342    fn push_to_nav_history(
13343        &mut self,
13344        cursor_anchor: Anchor,
13345        new_position: Option<Point>,
13346        is_deactivate: bool,
13347        always: bool,
13348        cx: &mut Context<Self>,
13349    ) {
13350        if let Some(nav_history) = self.nav_history.as_mut() {
13351            let buffer = self.buffer.read(cx).read(cx);
13352            let cursor_position = cursor_anchor.to_point(&buffer);
13353            let scroll_state = self.scroll_manager.anchor();
13354            let scroll_top_row = scroll_state.top_row(&buffer);
13355            drop(buffer);
13356
13357            if let Some(new_position) = new_position {
13358                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13359                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13360                    return;
13361                }
13362            }
13363
13364            nav_history.push(
13365                Some(NavigationData {
13366                    cursor_anchor,
13367                    cursor_position,
13368                    scroll_anchor: scroll_state,
13369                    scroll_top_row,
13370                }),
13371                cx,
13372            );
13373            cx.emit(EditorEvent::PushedToNavHistory {
13374                anchor: cursor_anchor,
13375                is_deactivate,
13376            })
13377        }
13378    }
13379
13380    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13381        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13382        let buffer = self.buffer.read(cx).snapshot(cx);
13383        let mut selection = self.selections.first::<usize>(cx);
13384        selection.set_head(buffer.len(), SelectionGoal::None);
13385        self.change_selections(Default::default(), window, cx, |s| {
13386            s.select(vec![selection]);
13387        });
13388    }
13389
13390    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13391        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13392        let end = self.buffer.read(cx).read(cx).len();
13393        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13394            s.select_ranges(vec![0..end]);
13395        });
13396    }
13397
13398    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13399        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13400        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13401        let mut selections = self.selections.all::<Point>(cx);
13402        let max_point = display_map.buffer_snapshot.max_point();
13403        for selection in &mut selections {
13404            let rows = selection.spanned_rows(true, &display_map);
13405            selection.start = Point::new(rows.start.0, 0);
13406            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13407            selection.reversed = false;
13408        }
13409        self.change_selections(Default::default(), window, cx, |s| {
13410            s.select(selections);
13411        });
13412    }
13413
13414    pub fn split_selection_into_lines(
13415        &mut self,
13416        _: &SplitSelectionIntoLines,
13417        window: &mut Window,
13418        cx: &mut Context<Self>,
13419    ) {
13420        let selections = self
13421            .selections
13422            .all::<Point>(cx)
13423            .into_iter()
13424            .map(|selection| selection.start..selection.end)
13425            .collect::<Vec<_>>();
13426        self.unfold_ranges(&selections, true, true, cx);
13427
13428        let mut new_selection_ranges = Vec::new();
13429        {
13430            let buffer = self.buffer.read(cx).read(cx);
13431            for selection in selections {
13432                for row in selection.start.row..selection.end.row {
13433                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13434                    new_selection_ranges.push(cursor..cursor);
13435                }
13436
13437                let is_multiline_selection = selection.start.row != selection.end.row;
13438                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13439                // so this action feels more ergonomic when paired with other selection operations
13440                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13441                if !should_skip_last {
13442                    new_selection_ranges.push(selection.end..selection.end);
13443                }
13444            }
13445        }
13446        self.change_selections(Default::default(), window, cx, |s| {
13447            s.select_ranges(new_selection_ranges);
13448        });
13449    }
13450
13451    pub fn add_selection_above(
13452        &mut self,
13453        _: &AddSelectionAbove,
13454        window: &mut Window,
13455        cx: &mut Context<Self>,
13456    ) {
13457        self.add_selection(true, window, cx);
13458    }
13459
13460    pub fn add_selection_below(
13461        &mut self,
13462        _: &AddSelectionBelow,
13463        window: &mut Window,
13464        cx: &mut Context<Self>,
13465    ) {
13466        self.add_selection(false, window, cx);
13467    }
13468
13469    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13470        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13471
13472        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13473        let all_selections = self.selections.all::<Point>(cx);
13474        let text_layout_details = self.text_layout_details(window);
13475
13476        let (mut columnar_selections, new_selections_to_columnarize) = {
13477            if let Some(state) = self.add_selections_state.as_ref() {
13478                let columnar_selection_ids: HashSet<_> = state
13479                    .groups
13480                    .iter()
13481                    .flat_map(|group| group.stack.iter())
13482                    .copied()
13483                    .collect();
13484
13485                all_selections
13486                    .into_iter()
13487                    .partition(|s| columnar_selection_ids.contains(&s.id))
13488            } else {
13489                (Vec::new(), all_selections)
13490            }
13491        };
13492
13493        let mut state = self
13494            .add_selections_state
13495            .take()
13496            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13497
13498        for selection in new_selections_to_columnarize {
13499            let range = selection.display_range(&display_map).sorted();
13500            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13501            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13502            let positions = start_x.min(end_x)..start_x.max(end_x);
13503            let mut stack = Vec::new();
13504            for row in range.start.row().0..=range.end.row().0 {
13505                if let Some(selection) = self.selections.build_columnar_selection(
13506                    &display_map,
13507                    DisplayRow(row),
13508                    &positions,
13509                    selection.reversed,
13510                    &text_layout_details,
13511                ) {
13512                    stack.push(selection.id);
13513                    columnar_selections.push(selection);
13514                }
13515            }
13516            if !stack.is_empty() {
13517                if above {
13518                    stack.reverse();
13519                }
13520                state.groups.push(AddSelectionsGroup { above, stack });
13521            }
13522        }
13523
13524        let mut final_selections = Vec::new();
13525        let end_row = if above {
13526            DisplayRow(0)
13527        } else {
13528            display_map.max_point().row()
13529        };
13530
13531        let mut last_added_item_per_group = HashMap::default();
13532        for group in state.groups.iter_mut() {
13533            if let Some(last_id) = group.stack.last() {
13534                last_added_item_per_group.insert(*last_id, group);
13535            }
13536        }
13537
13538        for selection in columnar_selections {
13539            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13540                if above == group.above {
13541                    let range = selection.display_range(&display_map).sorted();
13542                    debug_assert_eq!(range.start.row(), range.end.row());
13543                    let mut row = range.start.row();
13544                    let positions =
13545                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13546                            px(start)..px(end)
13547                        } else {
13548                            let start_x =
13549                                display_map.x_for_display_point(range.start, &text_layout_details);
13550                            let end_x =
13551                                display_map.x_for_display_point(range.end, &text_layout_details);
13552                            start_x.min(end_x)..start_x.max(end_x)
13553                        };
13554
13555                    let mut maybe_new_selection = None;
13556                    while row != end_row {
13557                        if above {
13558                            row.0 -= 1;
13559                        } else {
13560                            row.0 += 1;
13561                        }
13562                        if let Some(new_selection) = self.selections.build_columnar_selection(
13563                            &display_map,
13564                            row,
13565                            &positions,
13566                            selection.reversed,
13567                            &text_layout_details,
13568                        ) {
13569                            maybe_new_selection = Some(new_selection);
13570                            break;
13571                        }
13572                    }
13573
13574                    if let Some(new_selection) = maybe_new_selection {
13575                        group.stack.push(new_selection.id);
13576                        if above {
13577                            final_selections.push(new_selection);
13578                            final_selections.push(selection);
13579                        } else {
13580                            final_selections.push(selection);
13581                            final_selections.push(new_selection);
13582                        }
13583                    } else {
13584                        final_selections.push(selection);
13585                    }
13586                } else {
13587                    group.stack.pop();
13588                }
13589            } else {
13590                final_selections.push(selection);
13591            }
13592        }
13593
13594        self.change_selections(Default::default(), window, cx, |s| {
13595            s.select(final_selections);
13596        });
13597
13598        let final_selection_ids: HashSet<_> = self
13599            .selections
13600            .all::<Point>(cx)
13601            .iter()
13602            .map(|s| s.id)
13603            .collect();
13604        state.groups.retain_mut(|group| {
13605            // selections might get merged above so we remove invalid items from stacks
13606            group.stack.retain(|id| final_selection_ids.contains(id));
13607
13608            // single selection in stack can be treated as initial state
13609            group.stack.len() > 1
13610        });
13611
13612        if !state.groups.is_empty() {
13613            self.add_selections_state = Some(state);
13614        }
13615    }
13616
13617    fn select_match_ranges(
13618        &mut self,
13619        range: Range<usize>,
13620        reversed: bool,
13621        replace_newest: bool,
13622        auto_scroll: Option<Autoscroll>,
13623        window: &mut Window,
13624        cx: &mut Context<Editor>,
13625    ) {
13626        self.unfold_ranges(
13627            std::slice::from_ref(&range),
13628            false,
13629            auto_scroll.is_some(),
13630            cx,
13631        );
13632        let effects = if let Some(scroll) = auto_scroll {
13633            SelectionEffects::scroll(scroll)
13634        } else {
13635            SelectionEffects::no_scroll()
13636        };
13637        self.change_selections(effects, window, cx, |s| {
13638            if replace_newest {
13639                s.delete(s.newest_anchor().id);
13640            }
13641            if reversed {
13642                s.insert_range(range.end..range.start);
13643            } else {
13644                s.insert_range(range);
13645            }
13646        });
13647    }
13648
13649    pub fn select_next_match_internal(
13650        &mut self,
13651        display_map: &DisplaySnapshot,
13652        replace_newest: bool,
13653        autoscroll: Option<Autoscroll>,
13654        window: &mut Window,
13655        cx: &mut Context<Self>,
13656    ) -> Result<()> {
13657        let buffer = &display_map.buffer_snapshot;
13658        let mut selections = self.selections.all::<usize>(cx);
13659        if let Some(mut select_next_state) = self.select_next_state.take() {
13660            let query = &select_next_state.query;
13661            if !select_next_state.done {
13662                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13663                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13664                let mut next_selected_range = None;
13665
13666                let bytes_after_last_selection =
13667                    buffer.bytes_in_range(last_selection.end..buffer.len());
13668                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13669                let query_matches = query
13670                    .stream_find_iter(bytes_after_last_selection)
13671                    .map(|result| (last_selection.end, result))
13672                    .chain(
13673                        query
13674                            .stream_find_iter(bytes_before_first_selection)
13675                            .map(|result| (0, result)),
13676                    );
13677
13678                for (start_offset, query_match) in query_matches {
13679                    let query_match = query_match.unwrap(); // can only fail due to I/O
13680                    let offset_range =
13681                        start_offset + query_match.start()..start_offset + query_match.end();
13682
13683                    if !select_next_state.wordwise
13684                        || (!buffer.is_inside_word(offset_range.start, false)
13685                            && !buffer.is_inside_word(offset_range.end, false))
13686                    {
13687                        // TODO: This is n^2, because we might check all the selections
13688                        if !selections
13689                            .iter()
13690                            .any(|selection| selection.range().overlaps(&offset_range))
13691                        {
13692                            next_selected_range = Some(offset_range);
13693                            break;
13694                        }
13695                    }
13696                }
13697
13698                if let Some(next_selected_range) = next_selected_range {
13699                    self.select_match_ranges(
13700                        next_selected_range,
13701                        last_selection.reversed,
13702                        replace_newest,
13703                        autoscroll,
13704                        window,
13705                        cx,
13706                    );
13707                } else {
13708                    select_next_state.done = true;
13709                }
13710            }
13711
13712            self.select_next_state = Some(select_next_state);
13713        } else {
13714            let mut only_carets = true;
13715            let mut same_text_selected = true;
13716            let mut selected_text = None;
13717
13718            let mut selections_iter = selections.iter().peekable();
13719            while let Some(selection) = selections_iter.next() {
13720                if selection.start != selection.end {
13721                    only_carets = false;
13722                }
13723
13724                if same_text_selected {
13725                    if selected_text.is_none() {
13726                        selected_text =
13727                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13728                    }
13729
13730                    if let Some(next_selection) = selections_iter.peek() {
13731                        if next_selection.range().len() == selection.range().len() {
13732                            let next_selected_text = buffer
13733                                .text_for_range(next_selection.range())
13734                                .collect::<String>();
13735                            if Some(next_selected_text) != selected_text {
13736                                same_text_selected = false;
13737                                selected_text = None;
13738                            }
13739                        } else {
13740                            same_text_selected = false;
13741                            selected_text = None;
13742                        }
13743                    }
13744                }
13745            }
13746
13747            if only_carets {
13748                for selection in &mut selections {
13749                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13750                    selection.start = word_range.start;
13751                    selection.end = word_range.end;
13752                    selection.goal = SelectionGoal::None;
13753                    selection.reversed = false;
13754                    self.select_match_ranges(
13755                        selection.start..selection.end,
13756                        selection.reversed,
13757                        replace_newest,
13758                        autoscroll,
13759                        window,
13760                        cx,
13761                    );
13762                }
13763
13764                if selections.len() == 1 {
13765                    let selection = selections
13766                        .last()
13767                        .expect("ensured that there's only one selection");
13768                    let query = buffer
13769                        .text_for_range(selection.start..selection.end)
13770                        .collect::<String>();
13771                    let is_empty = query.is_empty();
13772                    let select_state = SelectNextState {
13773                        query: AhoCorasick::new(&[query])?,
13774                        wordwise: true,
13775                        done: is_empty,
13776                    };
13777                    self.select_next_state = Some(select_state);
13778                } else {
13779                    self.select_next_state = None;
13780                }
13781            } else if let Some(selected_text) = selected_text {
13782                self.select_next_state = Some(SelectNextState {
13783                    query: AhoCorasick::new(&[selected_text])?,
13784                    wordwise: false,
13785                    done: false,
13786                });
13787                self.select_next_match_internal(
13788                    display_map,
13789                    replace_newest,
13790                    autoscroll,
13791                    window,
13792                    cx,
13793                )?;
13794            }
13795        }
13796        Ok(())
13797    }
13798
13799    pub fn select_all_matches(
13800        &mut self,
13801        _action: &SelectAllMatches,
13802        window: &mut Window,
13803        cx: &mut Context<Self>,
13804    ) -> Result<()> {
13805        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13806
13807        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13808
13809        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13810        let Some(select_next_state) = self.select_next_state.as_mut() else {
13811            return Ok(());
13812        };
13813        if select_next_state.done {
13814            return Ok(());
13815        }
13816
13817        let mut new_selections = Vec::new();
13818
13819        let reversed = self.selections.oldest::<usize>(cx).reversed;
13820        let buffer = &display_map.buffer_snapshot;
13821        let query_matches = select_next_state
13822            .query
13823            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13824
13825        for query_match in query_matches.into_iter() {
13826            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13827            let offset_range = if reversed {
13828                query_match.end()..query_match.start()
13829            } else {
13830                query_match.start()..query_match.end()
13831            };
13832
13833            if !select_next_state.wordwise
13834                || (!buffer.is_inside_word(offset_range.start, false)
13835                    && !buffer.is_inside_word(offset_range.end, false))
13836            {
13837                new_selections.push(offset_range.start..offset_range.end);
13838            }
13839        }
13840
13841        select_next_state.done = true;
13842
13843        if new_selections.is_empty() {
13844            log::error!("bug: new_selections is empty in select_all_matches");
13845            return Ok(());
13846        }
13847
13848        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13849        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13850            selections.select_ranges(new_selections)
13851        });
13852
13853        Ok(())
13854    }
13855
13856    pub fn select_next(
13857        &mut self,
13858        action: &SelectNext,
13859        window: &mut Window,
13860        cx: &mut Context<Self>,
13861    ) -> Result<()> {
13862        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13863        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13864        self.select_next_match_internal(
13865            &display_map,
13866            action.replace_newest,
13867            Some(Autoscroll::newest()),
13868            window,
13869            cx,
13870        )?;
13871        Ok(())
13872    }
13873
13874    pub fn select_previous(
13875        &mut self,
13876        action: &SelectPrevious,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) -> Result<()> {
13880        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13881        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13882        let buffer = &display_map.buffer_snapshot;
13883        let mut selections = self.selections.all::<usize>(cx);
13884        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13885            let query = &select_prev_state.query;
13886            if !select_prev_state.done {
13887                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13888                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13889                let mut next_selected_range = None;
13890                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13891                let bytes_before_last_selection =
13892                    buffer.reversed_bytes_in_range(0..last_selection.start);
13893                let bytes_after_first_selection =
13894                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13895                let query_matches = query
13896                    .stream_find_iter(bytes_before_last_selection)
13897                    .map(|result| (last_selection.start, result))
13898                    .chain(
13899                        query
13900                            .stream_find_iter(bytes_after_first_selection)
13901                            .map(|result| (buffer.len(), result)),
13902                    );
13903                for (end_offset, query_match) in query_matches {
13904                    let query_match = query_match.unwrap(); // can only fail due to I/O
13905                    let offset_range =
13906                        end_offset - query_match.end()..end_offset - query_match.start();
13907
13908                    if !select_prev_state.wordwise
13909                        || (!buffer.is_inside_word(offset_range.start, false)
13910                            && !buffer.is_inside_word(offset_range.end, false))
13911                    {
13912                        next_selected_range = Some(offset_range);
13913                        break;
13914                    }
13915                }
13916
13917                if let Some(next_selected_range) = next_selected_range {
13918                    self.select_match_ranges(
13919                        next_selected_range,
13920                        last_selection.reversed,
13921                        action.replace_newest,
13922                        Some(Autoscroll::newest()),
13923                        window,
13924                        cx,
13925                    );
13926                } else {
13927                    select_prev_state.done = true;
13928                }
13929            }
13930
13931            self.select_prev_state = Some(select_prev_state);
13932        } else {
13933            let mut only_carets = true;
13934            let mut same_text_selected = true;
13935            let mut selected_text = None;
13936
13937            let mut selections_iter = selections.iter().peekable();
13938            while let Some(selection) = selections_iter.next() {
13939                if selection.start != selection.end {
13940                    only_carets = false;
13941                }
13942
13943                if same_text_selected {
13944                    if selected_text.is_none() {
13945                        selected_text =
13946                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13947                    }
13948
13949                    if let Some(next_selection) = selections_iter.peek() {
13950                        if next_selection.range().len() == selection.range().len() {
13951                            let next_selected_text = buffer
13952                                .text_for_range(next_selection.range())
13953                                .collect::<String>();
13954                            if Some(next_selected_text) != selected_text {
13955                                same_text_selected = false;
13956                                selected_text = None;
13957                            }
13958                        } else {
13959                            same_text_selected = false;
13960                            selected_text = None;
13961                        }
13962                    }
13963                }
13964            }
13965
13966            if only_carets {
13967                for selection in &mut selections {
13968                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13969                    selection.start = word_range.start;
13970                    selection.end = word_range.end;
13971                    selection.goal = SelectionGoal::None;
13972                    selection.reversed = false;
13973                    self.select_match_ranges(
13974                        selection.start..selection.end,
13975                        selection.reversed,
13976                        action.replace_newest,
13977                        Some(Autoscroll::newest()),
13978                        window,
13979                        cx,
13980                    );
13981                }
13982                if selections.len() == 1 {
13983                    let selection = selections
13984                        .last()
13985                        .expect("ensured that there's only one selection");
13986                    let query = buffer
13987                        .text_for_range(selection.start..selection.end)
13988                        .collect::<String>();
13989                    let is_empty = query.is_empty();
13990                    let select_state = SelectNextState {
13991                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13992                        wordwise: true,
13993                        done: is_empty,
13994                    };
13995                    self.select_prev_state = Some(select_state);
13996                } else {
13997                    self.select_prev_state = None;
13998                }
13999            } else if let Some(selected_text) = selected_text {
14000                self.select_prev_state = Some(SelectNextState {
14001                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14002                    wordwise: false,
14003                    done: false,
14004                });
14005                self.select_previous(action, window, cx)?;
14006            }
14007        }
14008        Ok(())
14009    }
14010
14011    pub fn find_next_match(
14012        &mut self,
14013        _: &FindNextMatch,
14014        window: &mut Window,
14015        cx: &mut Context<Self>,
14016    ) -> Result<()> {
14017        let selections = self.selections.disjoint_anchors();
14018        match selections.first() {
14019            Some(first) if selections.len() >= 2 => {
14020                self.change_selections(Default::default(), window, cx, |s| {
14021                    s.select_ranges([first.range()]);
14022                });
14023            }
14024            _ => self.select_next(
14025                &SelectNext {
14026                    replace_newest: true,
14027                },
14028                window,
14029                cx,
14030            )?,
14031        }
14032        Ok(())
14033    }
14034
14035    pub fn find_previous_match(
14036        &mut self,
14037        _: &FindPreviousMatch,
14038        window: &mut Window,
14039        cx: &mut Context<Self>,
14040    ) -> Result<()> {
14041        let selections = self.selections.disjoint_anchors();
14042        match selections.last() {
14043            Some(last) if selections.len() >= 2 => {
14044                self.change_selections(Default::default(), window, cx, |s| {
14045                    s.select_ranges([last.range()]);
14046                });
14047            }
14048            _ => self.select_previous(
14049                &SelectPrevious {
14050                    replace_newest: true,
14051                },
14052                window,
14053                cx,
14054            )?,
14055        }
14056        Ok(())
14057    }
14058
14059    pub fn toggle_comments(
14060        &mut self,
14061        action: &ToggleComments,
14062        window: &mut Window,
14063        cx: &mut Context<Self>,
14064    ) {
14065        if self.read_only(cx) {
14066            return;
14067        }
14068        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14069        let text_layout_details = &self.text_layout_details(window);
14070        self.transact(window, cx, |this, window, cx| {
14071            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14072            let mut edits = Vec::new();
14073            let mut selection_edit_ranges = Vec::new();
14074            let mut last_toggled_row = None;
14075            let snapshot = this.buffer.read(cx).read(cx);
14076            let empty_str: Arc<str> = Arc::default();
14077            let mut suffixes_inserted = Vec::new();
14078            let ignore_indent = action.ignore_indent;
14079
14080            fn comment_prefix_range(
14081                snapshot: &MultiBufferSnapshot,
14082                row: MultiBufferRow,
14083                comment_prefix: &str,
14084                comment_prefix_whitespace: &str,
14085                ignore_indent: bool,
14086            ) -> Range<Point> {
14087                let indent_size = if ignore_indent {
14088                    0
14089                } else {
14090                    snapshot.indent_size_for_line(row).len
14091                };
14092
14093                let start = Point::new(row.0, indent_size);
14094
14095                let mut line_bytes = snapshot
14096                    .bytes_in_range(start..snapshot.max_point())
14097                    .flatten()
14098                    .copied();
14099
14100                // If this line currently begins with the line comment prefix, then record
14101                // the range containing the prefix.
14102                if line_bytes
14103                    .by_ref()
14104                    .take(comment_prefix.len())
14105                    .eq(comment_prefix.bytes())
14106                {
14107                    // Include any whitespace that matches the comment prefix.
14108                    let matching_whitespace_len = line_bytes
14109                        .zip(comment_prefix_whitespace.bytes())
14110                        .take_while(|(a, b)| a == b)
14111                        .count() as u32;
14112                    let end = Point::new(
14113                        start.row,
14114                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14115                    );
14116                    start..end
14117                } else {
14118                    start..start
14119                }
14120            }
14121
14122            fn comment_suffix_range(
14123                snapshot: &MultiBufferSnapshot,
14124                row: MultiBufferRow,
14125                comment_suffix: &str,
14126                comment_suffix_has_leading_space: bool,
14127            ) -> Range<Point> {
14128                let end = Point::new(row.0, snapshot.line_len(row));
14129                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14130
14131                let mut line_end_bytes = snapshot
14132                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14133                    .flatten()
14134                    .copied();
14135
14136                let leading_space_len = if suffix_start_column > 0
14137                    && line_end_bytes.next() == Some(b' ')
14138                    && comment_suffix_has_leading_space
14139                {
14140                    1
14141                } else {
14142                    0
14143                };
14144
14145                // If this line currently begins with the line comment prefix, then record
14146                // the range containing the prefix.
14147                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14148                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14149                    start..end
14150                } else {
14151                    end..end
14152                }
14153            }
14154
14155            // TODO: Handle selections that cross excerpts
14156            for selection in &mut selections {
14157                let start_column = snapshot
14158                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14159                    .len;
14160                let language = if let Some(language) =
14161                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14162                {
14163                    language
14164                } else {
14165                    continue;
14166                };
14167
14168                selection_edit_ranges.clear();
14169
14170                // If multiple selections contain a given row, avoid processing that
14171                // row more than once.
14172                let mut start_row = MultiBufferRow(selection.start.row);
14173                if last_toggled_row == Some(start_row) {
14174                    start_row = start_row.next_row();
14175                }
14176                let end_row =
14177                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14178                        MultiBufferRow(selection.end.row - 1)
14179                    } else {
14180                        MultiBufferRow(selection.end.row)
14181                    };
14182                last_toggled_row = Some(end_row);
14183
14184                if start_row > end_row {
14185                    continue;
14186                }
14187
14188                // If the language has line comments, toggle those.
14189                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14190
14191                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14192                if ignore_indent {
14193                    full_comment_prefixes = full_comment_prefixes
14194                        .into_iter()
14195                        .map(|s| Arc::from(s.trim_end()))
14196                        .collect();
14197                }
14198
14199                if !full_comment_prefixes.is_empty() {
14200                    let first_prefix = full_comment_prefixes
14201                        .first()
14202                        .expect("prefixes is non-empty");
14203                    let prefix_trimmed_lengths = full_comment_prefixes
14204                        .iter()
14205                        .map(|p| p.trim_end_matches(' ').len())
14206                        .collect::<SmallVec<[usize; 4]>>();
14207
14208                    let mut all_selection_lines_are_comments = true;
14209
14210                    for row in start_row.0..=end_row.0 {
14211                        let row = MultiBufferRow(row);
14212                        if start_row < end_row && snapshot.is_line_blank(row) {
14213                            continue;
14214                        }
14215
14216                        let prefix_range = full_comment_prefixes
14217                            .iter()
14218                            .zip(prefix_trimmed_lengths.iter().copied())
14219                            .map(|(prefix, trimmed_prefix_len)| {
14220                                comment_prefix_range(
14221                                    snapshot.deref(),
14222                                    row,
14223                                    &prefix[..trimmed_prefix_len],
14224                                    &prefix[trimmed_prefix_len..],
14225                                    ignore_indent,
14226                                )
14227                            })
14228                            .max_by_key(|range| range.end.column - range.start.column)
14229                            .expect("prefixes is non-empty");
14230
14231                        if prefix_range.is_empty() {
14232                            all_selection_lines_are_comments = false;
14233                        }
14234
14235                        selection_edit_ranges.push(prefix_range);
14236                    }
14237
14238                    if all_selection_lines_are_comments {
14239                        edits.extend(
14240                            selection_edit_ranges
14241                                .iter()
14242                                .cloned()
14243                                .map(|range| (range, empty_str.clone())),
14244                        );
14245                    } else {
14246                        let min_column = selection_edit_ranges
14247                            .iter()
14248                            .map(|range| range.start.column)
14249                            .min()
14250                            .unwrap_or(0);
14251                        edits.extend(selection_edit_ranges.iter().map(|range| {
14252                            let position = Point::new(range.start.row, min_column);
14253                            (position..position, first_prefix.clone())
14254                        }));
14255                    }
14256                } else if let Some((full_comment_prefix, comment_suffix)) =
14257                    language.block_comment_delimiters()
14258                {
14259                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14260                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14261                    let prefix_range = comment_prefix_range(
14262                        snapshot.deref(),
14263                        start_row,
14264                        comment_prefix,
14265                        comment_prefix_whitespace,
14266                        ignore_indent,
14267                    );
14268                    let suffix_range = comment_suffix_range(
14269                        snapshot.deref(),
14270                        end_row,
14271                        comment_suffix.trim_start_matches(' '),
14272                        comment_suffix.starts_with(' '),
14273                    );
14274
14275                    if prefix_range.is_empty() || suffix_range.is_empty() {
14276                        edits.push((
14277                            prefix_range.start..prefix_range.start,
14278                            full_comment_prefix.clone(),
14279                        ));
14280                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14281                        suffixes_inserted.push((end_row, comment_suffix.len()));
14282                    } else {
14283                        edits.push((prefix_range, empty_str.clone()));
14284                        edits.push((suffix_range, empty_str.clone()));
14285                    }
14286                } else {
14287                    continue;
14288                }
14289            }
14290
14291            drop(snapshot);
14292            this.buffer.update(cx, |buffer, cx| {
14293                buffer.edit(edits, None, cx);
14294            });
14295
14296            // Adjust selections so that they end before any comment suffixes that
14297            // were inserted.
14298            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14299            let mut selections = this.selections.all::<Point>(cx);
14300            let snapshot = this.buffer.read(cx).read(cx);
14301            for selection in &mut selections {
14302                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14303                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14304                        Ordering::Less => {
14305                            suffixes_inserted.next();
14306                            continue;
14307                        }
14308                        Ordering::Greater => break,
14309                        Ordering::Equal => {
14310                            if selection.end.column == snapshot.line_len(row) {
14311                                if selection.is_empty() {
14312                                    selection.start.column -= suffix_len as u32;
14313                                }
14314                                selection.end.column -= suffix_len as u32;
14315                            }
14316                            break;
14317                        }
14318                    }
14319                }
14320            }
14321
14322            drop(snapshot);
14323            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14324
14325            let selections = this.selections.all::<Point>(cx);
14326            let selections_on_single_row = selections.windows(2).all(|selections| {
14327                selections[0].start.row == selections[1].start.row
14328                    && selections[0].end.row == selections[1].end.row
14329                    && selections[0].start.row == selections[0].end.row
14330            });
14331            let selections_selecting = selections
14332                .iter()
14333                .any(|selection| selection.start != selection.end);
14334            let advance_downwards = action.advance_downwards
14335                && selections_on_single_row
14336                && !selections_selecting
14337                && !matches!(this.mode, EditorMode::SingleLine { .. });
14338
14339            if advance_downwards {
14340                let snapshot = this.buffer.read(cx).snapshot(cx);
14341
14342                this.change_selections(Default::default(), window, cx, |s| {
14343                    s.move_cursors_with(|display_snapshot, display_point, _| {
14344                        let mut point = display_point.to_point(display_snapshot);
14345                        point.row += 1;
14346                        point = snapshot.clip_point(point, Bias::Left);
14347                        let display_point = point.to_display_point(display_snapshot);
14348                        let goal = SelectionGoal::HorizontalPosition(
14349                            display_snapshot
14350                                .x_for_display_point(display_point, text_layout_details)
14351                                .into(),
14352                        );
14353                        (display_point, goal)
14354                    })
14355                });
14356            }
14357        });
14358    }
14359
14360    pub fn select_enclosing_symbol(
14361        &mut self,
14362        _: &SelectEnclosingSymbol,
14363        window: &mut Window,
14364        cx: &mut Context<Self>,
14365    ) {
14366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14367
14368        let buffer = self.buffer.read(cx).snapshot(cx);
14369        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14370
14371        fn update_selection(
14372            selection: &Selection<usize>,
14373            buffer_snap: &MultiBufferSnapshot,
14374        ) -> Option<Selection<usize>> {
14375            let cursor = selection.head();
14376            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14377            for symbol in symbols.iter().rev() {
14378                let start = symbol.range.start.to_offset(buffer_snap);
14379                let end = symbol.range.end.to_offset(buffer_snap);
14380                let new_range = start..end;
14381                if start < selection.start || end > selection.end {
14382                    return Some(Selection {
14383                        id: selection.id,
14384                        start: new_range.start,
14385                        end: new_range.end,
14386                        goal: SelectionGoal::None,
14387                        reversed: selection.reversed,
14388                    });
14389                }
14390            }
14391            None
14392        }
14393
14394        let mut selected_larger_symbol = false;
14395        let new_selections = old_selections
14396            .iter()
14397            .map(|selection| match update_selection(selection, &buffer) {
14398                Some(new_selection) => {
14399                    if new_selection.range() != selection.range() {
14400                        selected_larger_symbol = true;
14401                    }
14402                    new_selection
14403                }
14404                None => selection.clone(),
14405            })
14406            .collect::<Vec<_>>();
14407
14408        if selected_larger_symbol {
14409            self.change_selections(Default::default(), window, cx, |s| {
14410                s.select(new_selections);
14411            });
14412        }
14413    }
14414
14415    pub fn select_larger_syntax_node(
14416        &mut self,
14417        _: &SelectLargerSyntaxNode,
14418        window: &mut Window,
14419        cx: &mut Context<Self>,
14420    ) {
14421        let Some(visible_row_count) = self.visible_row_count() else {
14422            return;
14423        };
14424        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14425        if old_selections.is_empty() {
14426            return;
14427        }
14428
14429        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14430
14431        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14432        let buffer = self.buffer.read(cx).snapshot(cx);
14433
14434        let mut selected_larger_node = false;
14435        let mut new_selections = old_selections
14436            .iter()
14437            .map(|selection| {
14438                let old_range = selection.start..selection.end;
14439
14440                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14441                    // manually select word at selection
14442                    if ["string_content", "inline"].contains(&node.kind()) {
14443                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14444                        // ignore if word is already selected
14445                        if !word_range.is_empty() && old_range != word_range {
14446                            let (last_word_range, _) =
14447                                buffer.surrounding_word(old_range.end, false);
14448                            // only select word if start and end point belongs to same word
14449                            if word_range == last_word_range {
14450                                selected_larger_node = true;
14451                                return Selection {
14452                                    id: selection.id,
14453                                    start: word_range.start,
14454                                    end: word_range.end,
14455                                    goal: SelectionGoal::None,
14456                                    reversed: selection.reversed,
14457                                };
14458                            }
14459                        }
14460                    }
14461                }
14462
14463                let mut new_range = old_range.clone();
14464                while let Some((_node, containing_range)) =
14465                    buffer.syntax_ancestor(new_range.clone())
14466                {
14467                    new_range = match containing_range {
14468                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14469                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14470                    };
14471                    if !display_map.intersects_fold(new_range.start)
14472                        && !display_map.intersects_fold(new_range.end)
14473                    {
14474                        break;
14475                    }
14476                }
14477
14478                selected_larger_node |= new_range != old_range;
14479                Selection {
14480                    id: selection.id,
14481                    start: new_range.start,
14482                    end: new_range.end,
14483                    goal: SelectionGoal::None,
14484                    reversed: selection.reversed,
14485                }
14486            })
14487            .collect::<Vec<_>>();
14488
14489        if !selected_larger_node {
14490            return; // don't put this call in the history
14491        }
14492
14493        // scroll based on transformation done to the last selection created by the user
14494        let (last_old, last_new) = old_selections
14495            .last()
14496            .zip(new_selections.last().cloned())
14497            .expect("old_selections isn't empty");
14498
14499        // revert selection
14500        let is_selection_reversed = {
14501            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14502            new_selections.last_mut().expect("checked above").reversed =
14503                should_newest_selection_be_reversed;
14504            should_newest_selection_be_reversed
14505        };
14506
14507        if selected_larger_node {
14508            self.select_syntax_node_history.disable_clearing = true;
14509            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14510                s.select(new_selections.clone());
14511            });
14512            self.select_syntax_node_history.disable_clearing = false;
14513        }
14514
14515        let start_row = last_new.start.to_display_point(&display_map).row().0;
14516        let end_row = last_new.end.to_display_point(&display_map).row().0;
14517        let selection_height = end_row - start_row + 1;
14518        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14519
14520        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14521        let scroll_behavior = if fits_on_the_screen {
14522            self.request_autoscroll(Autoscroll::fit(), cx);
14523            SelectSyntaxNodeScrollBehavior::FitSelection
14524        } else if is_selection_reversed {
14525            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14526            SelectSyntaxNodeScrollBehavior::CursorTop
14527        } else {
14528            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14529            SelectSyntaxNodeScrollBehavior::CursorBottom
14530        };
14531
14532        self.select_syntax_node_history.push((
14533            old_selections,
14534            scroll_behavior,
14535            is_selection_reversed,
14536        ));
14537    }
14538
14539    pub fn select_smaller_syntax_node(
14540        &mut self,
14541        _: &SelectSmallerSyntaxNode,
14542        window: &mut Window,
14543        cx: &mut Context<Self>,
14544    ) {
14545        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14546
14547        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14548            self.select_syntax_node_history.pop()
14549        {
14550            if let Some(selection) = selections.last_mut() {
14551                selection.reversed = is_selection_reversed;
14552            }
14553
14554            self.select_syntax_node_history.disable_clearing = true;
14555            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14556                s.select(selections.to_vec());
14557            });
14558            self.select_syntax_node_history.disable_clearing = false;
14559
14560            match scroll_behavior {
14561                SelectSyntaxNodeScrollBehavior::CursorTop => {
14562                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14563                }
14564                SelectSyntaxNodeScrollBehavior::FitSelection => {
14565                    self.request_autoscroll(Autoscroll::fit(), cx);
14566                }
14567                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14568                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14569                }
14570            }
14571        }
14572    }
14573
14574    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14575        if !EditorSettings::get_global(cx).gutter.runnables {
14576            self.clear_tasks();
14577            return Task::ready(());
14578        }
14579        let project = self.project.as_ref().map(Entity::downgrade);
14580        let task_sources = self.lsp_task_sources(cx);
14581        let multi_buffer = self.buffer.downgrade();
14582        cx.spawn_in(window, async move |editor, cx| {
14583            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14584            let Some(project) = project.and_then(|p| p.upgrade()) else {
14585                return;
14586            };
14587            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14588                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14589            }) else {
14590                return;
14591            };
14592
14593            let hide_runnables = project
14594                .update(cx, |project, cx| {
14595                    // Do not display any test indicators in non-dev server remote projects.
14596                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14597                })
14598                .unwrap_or(true);
14599            if hide_runnables {
14600                return;
14601            }
14602            let new_rows =
14603                cx.background_spawn({
14604                    let snapshot = display_snapshot.clone();
14605                    async move {
14606                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14607                    }
14608                })
14609                    .await;
14610            let Ok(lsp_tasks) =
14611                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14612            else {
14613                return;
14614            };
14615            let lsp_tasks = lsp_tasks.await;
14616
14617            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14618                lsp_tasks
14619                    .into_iter()
14620                    .flat_map(|(kind, tasks)| {
14621                        tasks.into_iter().filter_map(move |(location, task)| {
14622                            Some((kind.clone(), location?, task))
14623                        })
14624                    })
14625                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14626                        let buffer = location.target.buffer;
14627                        let buffer_snapshot = buffer.read(cx).snapshot();
14628                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14629                            |(excerpt_id, snapshot, _)| {
14630                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14631                                    display_snapshot
14632                                        .buffer_snapshot
14633                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14634                                } else {
14635                                    None
14636                                }
14637                            },
14638                        );
14639                        if let Some(offset) = offset {
14640                            let task_buffer_range =
14641                                location.target.range.to_point(&buffer_snapshot);
14642                            let context_buffer_range =
14643                                task_buffer_range.to_offset(&buffer_snapshot);
14644                            let context_range = BufferOffset(context_buffer_range.start)
14645                                ..BufferOffset(context_buffer_range.end);
14646
14647                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14648                                .or_insert_with(|| RunnableTasks {
14649                                    templates: Vec::new(),
14650                                    offset,
14651                                    column: task_buffer_range.start.column,
14652                                    extra_variables: HashMap::default(),
14653                                    context_range,
14654                                })
14655                                .templates
14656                                .push((kind, task.original_task().clone()));
14657                        }
14658
14659                        acc
14660                    })
14661            }) else {
14662                return;
14663            };
14664
14665            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14666                buffer.language_settings(cx).tasks.prefer_lsp
14667            }) else {
14668                return;
14669            };
14670
14671            let rows = Self::runnable_rows(
14672                project,
14673                display_snapshot,
14674                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14675                new_rows,
14676                cx.clone(),
14677            )
14678            .await;
14679            editor
14680                .update(cx, |editor, _| {
14681                    editor.clear_tasks();
14682                    for (key, mut value) in rows {
14683                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14684                            value.templates.extend(lsp_tasks.templates);
14685                        }
14686
14687                        editor.insert_tasks(key, value);
14688                    }
14689                    for (key, value) in lsp_tasks_by_rows {
14690                        editor.insert_tasks(key, value);
14691                    }
14692                })
14693                .ok();
14694        })
14695    }
14696    fn fetch_runnable_ranges(
14697        snapshot: &DisplaySnapshot,
14698        range: Range<Anchor>,
14699    ) -> Vec<language::RunnableRange> {
14700        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14701    }
14702
14703    fn runnable_rows(
14704        project: Entity<Project>,
14705        snapshot: DisplaySnapshot,
14706        prefer_lsp: bool,
14707        runnable_ranges: Vec<RunnableRange>,
14708        cx: AsyncWindowContext,
14709    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14710        cx.spawn(async move |cx| {
14711            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14712            for mut runnable in runnable_ranges {
14713                let Some(tasks) = cx
14714                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14715                    .ok()
14716                else {
14717                    continue;
14718                };
14719                let mut tasks = tasks.await;
14720
14721                if prefer_lsp {
14722                    tasks.retain(|(task_kind, _)| {
14723                        !matches!(task_kind, TaskSourceKind::Language { .. })
14724                    });
14725                }
14726                if tasks.is_empty() {
14727                    continue;
14728                }
14729
14730                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14731                let Some(row) = snapshot
14732                    .buffer_snapshot
14733                    .buffer_line_for_row(MultiBufferRow(point.row))
14734                    .map(|(_, range)| range.start.row)
14735                else {
14736                    continue;
14737                };
14738
14739                let context_range =
14740                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14741                runnable_rows.push((
14742                    (runnable.buffer_id, row),
14743                    RunnableTasks {
14744                        templates: tasks,
14745                        offset: snapshot
14746                            .buffer_snapshot
14747                            .anchor_before(runnable.run_range.start),
14748                        context_range,
14749                        column: point.column,
14750                        extra_variables: runnable.extra_captures,
14751                    },
14752                ));
14753            }
14754            runnable_rows
14755        })
14756    }
14757
14758    fn templates_with_tags(
14759        project: &Entity<Project>,
14760        runnable: &mut Runnable,
14761        cx: &mut App,
14762    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14763        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14764            let (worktree_id, file) = project
14765                .buffer_for_id(runnable.buffer, cx)
14766                .and_then(|buffer| buffer.read(cx).file())
14767                .map(|file| (file.worktree_id(cx), file.clone()))
14768                .unzip();
14769
14770            (
14771                project.task_store().read(cx).task_inventory().cloned(),
14772                worktree_id,
14773                file,
14774            )
14775        });
14776
14777        let tags = mem::take(&mut runnable.tags);
14778        let language = runnable.language.clone();
14779        cx.spawn(async move |cx| {
14780            let mut templates_with_tags = Vec::new();
14781            if let Some(inventory) = inventory {
14782                for RunnableTag(tag) in tags {
14783                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14784                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14785                    }) else {
14786                        return templates_with_tags;
14787                    };
14788                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14789                        move |(_, template)| {
14790                            template.tags.iter().any(|source_tag| source_tag == &tag)
14791                        },
14792                    ));
14793                }
14794            }
14795            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14796
14797            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14798                // Strongest source wins; if we have worktree tag binding, prefer that to
14799                // global and language bindings;
14800                // if we have a global binding, prefer that to language binding.
14801                let first_mismatch = templates_with_tags
14802                    .iter()
14803                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14804                if let Some(index) = first_mismatch {
14805                    templates_with_tags.truncate(index);
14806                }
14807            }
14808
14809            templates_with_tags
14810        })
14811    }
14812
14813    pub fn move_to_enclosing_bracket(
14814        &mut self,
14815        _: &MoveToEnclosingBracket,
14816        window: &mut Window,
14817        cx: &mut Context<Self>,
14818    ) {
14819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14820        self.change_selections(Default::default(), window, cx, |s| {
14821            s.move_offsets_with(|snapshot, selection| {
14822                let Some(enclosing_bracket_ranges) =
14823                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14824                else {
14825                    return;
14826                };
14827
14828                let mut best_length = usize::MAX;
14829                let mut best_inside = false;
14830                let mut best_in_bracket_range = false;
14831                let mut best_destination = None;
14832                for (open, close) in enclosing_bracket_ranges {
14833                    let close = close.to_inclusive();
14834                    let length = close.end() - open.start;
14835                    let inside = selection.start >= open.end && selection.end <= *close.start();
14836                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14837                        || close.contains(&selection.head());
14838
14839                    // If best is next to a bracket and current isn't, skip
14840                    if !in_bracket_range && best_in_bracket_range {
14841                        continue;
14842                    }
14843
14844                    // Prefer smaller lengths unless best is inside and current isn't
14845                    if length > best_length && (best_inside || !inside) {
14846                        continue;
14847                    }
14848
14849                    best_length = length;
14850                    best_inside = inside;
14851                    best_in_bracket_range = in_bracket_range;
14852                    best_destination = Some(
14853                        if close.contains(&selection.start) && close.contains(&selection.end) {
14854                            if inside { open.end } else { open.start }
14855                        } else if inside {
14856                            *close.start()
14857                        } else {
14858                            *close.end()
14859                        },
14860                    );
14861                }
14862
14863                if let Some(destination) = best_destination {
14864                    selection.collapse_to(destination, SelectionGoal::None);
14865                }
14866            })
14867        });
14868    }
14869
14870    pub fn undo_selection(
14871        &mut self,
14872        _: &UndoSelection,
14873        window: &mut Window,
14874        cx: &mut Context<Self>,
14875    ) {
14876        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14877        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14878            self.selection_history.mode = SelectionHistoryMode::Undoing;
14879            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14880                this.end_selection(window, cx);
14881                this.change_selections(
14882                    SelectionEffects::scroll(Autoscroll::newest()),
14883                    window,
14884                    cx,
14885                    |s| s.select_anchors(entry.selections.to_vec()),
14886                );
14887            });
14888            self.selection_history.mode = SelectionHistoryMode::Normal;
14889
14890            self.select_next_state = entry.select_next_state;
14891            self.select_prev_state = entry.select_prev_state;
14892            self.add_selections_state = entry.add_selections_state;
14893        }
14894    }
14895
14896    pub fn redo_selection(
14897        &mut self,
14898        _: &RedoSelection,
14899        window: &mut Window,
14900        cx: &mut Context<Self>,
14901    ) {
14902        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14903        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14904            self.selection_history.mode = SelectionHistoryMode::Redoing;
14905            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14906                this.end_selection(window, cx);
14907                this.change_selections(
14908                    SelectionEffects::scroll(Autoscroll::newest()),
14909                    window,
14910                    cx,
14911                    |s| s.select_anchors(entry.selections.to_vec()),
14912                );
14913            });
14914            self.selection_history.mode = SelectionHistoryMode::Normal;
14915
14916            self.select_next_state = entry.select_next_state;
14917            self.select_prev_state = entry.select_prev_state;
14918            self.add_selections_state = entry.add_selections_state;
14919        }
14920    }
14921
14922    pub fn expand_excerpts(
14923        &mut self,
14924        action: &ExpandExcerpts,
14925        _: &mut Window,
14926        cx: &mut Context<Self>,
14927    ) {
14928        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14929    }
14930
14931    pub fn expand_excerpts_down(
14932        &mut self,
14933        action: &ExpandExcerptsDown,
14934        _: &mut Window,
14935        cx: &mut Context<Self>,
14936    ) {
14937        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14938    }
14939
14940    pub fn expand_excerpts_up(
14941        &mut self,
14942        action: &ExpandExcerptsUp,
14943        _: &mut Window,
14944        cx: &mut Context<Self>,
14945    ) {
14946        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14947    }
14948
14949    pub fn expand_excerpts_for_direction(
14950        &mut self,
14951        lines: u32,
14952        direction: ExpandExcerptDirection,
14953
14954        cx: &mut Context<Self>,
14955    ) {
14956        let selections = self.selections.disjoint_anchors();
14957
14958        let lines = if lines == 0 {
14959            EditorSettings::get_global(cx).expand_excerpt_lines
14960        } else {
14961            lines
14962        };
14963
14964        self.buffer.update(cx, |buffer, cx| {
14965            let snapshot = buffer.snapshot(cx);
14966            let mut excerpt_ids = selections
14967                .iter()
14968                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14969                .collect::<Vec<_>>();
14970            excerpt_ids.sort();
14971            excerpt_ids.dedup();
14972            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14973        })
14974    }
14975
14976    pub fn expand_excerpt(
14977        &mut self,
14978        excerpt: ExcerptId,
14979        direction: ExpandExcerptDirection,
14980        window: &mut Window,
14981        cx: &mut Context<Self>,
14982    ) {
14983        let current_scroll_position = self.scroll_position(cx);
14984        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14985        let mut should_scroll_up = false;
14986
14987        if direction == ExpandExcerptDirection::Down {
14988            let multi_buffer = self.buffer.read(cx);
14989            let snapshot = multi_buffer.snapshot(cx);
14990            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14991                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14992                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14993                        let buffer_snapshot = buffer.read(cx).snapshot();
14994                        let excerpt_end_row =
14995                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14996                        let last_row = buffer_snapshot.max_point().row;
14997                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14998                        should_scroll_up = lines_below >= lines_to_expand;
14999                    }
15000                }
15001            }
15002        }
15003
15004        self.buffer.update(cx, |buffer, cx| {
15005            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15006        });
15007
15008        if should_scroll_up {
15009            let new_scroll_position =
15010                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15011            self.set_scroll_position(new_scroll_position, window, cx);
15012        }
15013    }
15014
15015    pub fn go_to_singleton_buffer_point(
15016        &mut self,
15017        point: Point,
15018        window: &mut Window,
15019        cx: &mut Context<Self>,
15020    ) {
15021        self.go_to_singleton_buffer_range(point..point, window, cx);
15022    }
15023
15024    pub fn go_to_singleton_buffer_range(
15025        &mut self,
15026        range: Range<Point>,
15027        window: &mut Window,
15028        cx: &mut Context<Self>,
15029    ) {
15030        let multibuffer = self.buffer().read(cx);
15031        let Some(buffer) = multibuffer.as_singleton() else {
15032            return;
15033        };
15034        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15035            return;
15036        };
15037        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15038            return;
15039        };
15040        self.change_selections(
15041            SelectionEffects::default().nav_history(true),
15042            window,
15043            cx,
15044            |s| s.select_anchor_ranges([start..end]),
15045        );
15046    }
15047
15048    pub fn go_to_diagnostic(
15049        &mut self,
15050        _: &GoToDiagnostic,
15051        window: &mut Window,
15052        cx: &mut Context<Self>,
15053    ) {
15054        if !self.diagnostics_enabled() {
15055            return;
15056        }
15057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15058        self.go_to_diagnostic_impl(Direction::Next, window, cx)
15059    }
15060
15061    pub fn go_to_prev_diagnostic(
15062        &mut self,
15063        _: &GoToPreviousDiagnostic,
15064        window: &mut Window,
15065        cx: &mut Context<Self>,
15066    ) {
15067        if !self.diagnostics_enabled() {
15068            return;
15069        }
15070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15071        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
15072    }
15073
15074    pub fn go_to_diagnostic_impl(
15075        &mut self,
15076        direction: Direction,
15077        window: &mut Window,
15078        cx: &mut Context<Self>,
15079    ) {
15080        let buffer = self.buffer.read(cx).snapshot(cx);
15081        let selection = self.selections.newest::<usize>(cx);
15082
15083        let mut active_group_id = None;
15084        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15085            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15086                active_group_id = Some(active_group.group_id);
15087            }
15088        }
15089
15090        fn filtered(
15091            snapshot: EditorSnapshot,
15092            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15093        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15094            diagnostics
15095                .filter(|entry| entry.range.start != entry.range.end)
15096                .filter(|entry| !entry.diagnostic.is_unnecessary)
15097                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15098        }
15099
15100        let snapshot = self.snapshot(window, cx);
15101        let before = filtered(
15102            snapshot.clone(),
15103            buffer
15104                .diagnostics_in_range(0..selection.start)
15105                .filter(|entry| entry.range.start <= selection.start),
15106        );
15107        let after = filtered(
15108            snapshot,
15109            buffer
15110                .diagnostics_in_range(selection.start..buffer.len())
15111                .filter(|entry| entry.range.start >= selection.start),
15112        );
15113
15114        let mut found: Option<DiagnosticEntry<usize>> = None;
15115        if direction == Direction::Prev {
15116            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15117            {
15118                for diagnostic in prev_diagnostics.into_iter().rev() {
15119                    if diagnostic.range.start != selection.start
15120                        || active_group_id
15121                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15122                    {
15123                        found = Some(diagnostic);
15124                        break 'outer;
15125                    }
15126                }
15127            }
15128        } else {
15129            for diagnostic in after.chain(before) {
15130                if diagnostic.range.start != selection.start
15131                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15132                {
15133                    found = Some(diagnostic);
15134                    break;
15135                }
15136            }
15137        }
15138        let Some(next_diagnostic) = found else {
15139            return;
15140        };
15141
15142        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15143            return;
15144        };
15145        self.change_selections(Default::default(), window, cx, |s| {
15146            s.select_ranges(vec![
15147                next_diagnostic.range.start..next_diagnostic.range.start,
15148            ])
15149        });
15150        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15151        self.refresh_inline_completion(false, true, window, cx);
15152    }
15153
15154    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15156        let snapshot = self.snapshot(window, cx);
15157        let selection = self.selections.newest::<Point>(cx);
15158        self.go_to_hunk_before_or_after_position(
15159            &snapshot,
15160            selection.head(),
15161            Direction::Next,
15162            window,
15163            cx,
15164        );
15165    }
15166
15167    pub fn go_to_hunk_before_or_after_position(
15168        &mut self,
15169        snapshot: &EditorSnapshot,
15170        position: Point,
15171        direction: Direction,
15172        window: &mut Window,
15173        cx: &mut Context<Editor>,
15174    ) {
15175        let row = if direction == Direction::Next {
15176            self.hunk_after_position(snapshot, position)
15177                .map(|hunk| hunk.row_range.start)
15178        } else {
15179            self.hunk_before_position(snapshot, position)
15180        };
15181
15182        if let Some(row) = row {
15183            let destination = Point::new(row.0, 0);
15184            let autoscroll = Autoscroll::center();
15185
15186            self.unfold_ranges(&[destination..destination], false, false, cx);
15187            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15188                s.select_ranges([destination..destination]);
15189            });
15190        }
15191    }
15192
15193    fn hunk_after_position(
15194        &mut self,
15195        snapshot: &EditorSnapshot,
15196        position: Point,
15197    ) -> Option<MultiBufferDiffHunk> {
15198        snapshot
15199            .buffer_snapshot
15200            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15201            .find(|hunk| hunk.row_range.start.0 > position.row)
15202            .or_else(|| {
15203                snapshot
15204                    .buffer_snapshot
15205                    .diff_hunks_in_range(Point::zero()..position)
15206                    .find(|hunk| hunk.row_range.end.0 < position.row)
15207            })
15208    }
15209
15210    fn go_to_prev_hunk(
15211        &mut self,
15212        _: &GoToPreviousHunk,
15213        window: &mut Window,
15214        cx: &mut Context<Self>,
15215    ) {
15216        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15217        let snapshot = self.snapshot(window, cx);
15218        let selection = self.selections.newest::<Point>(cx);
15219        self.go_to_hunk_before_or_after_position(
15220            &snapshot,
15221            selection.head(),
15222            Direction::Prev,
15223            window,
15224            cx,
15225        );
15226    }
15227
15228    fn hunk_before_position(
15229        &mut self,
15230        snapshot: &EditorSnapshot,
15231        position: Point,
15232    ) -> Option<MultiBufferRow> {
15233        snapshot
15234            .buffer_snapshot
15235            .diff_hunk_before(position)
15236            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15237    }
15238
15239    fn go_to_next_change(
15240        &mut self,
15241        _: &GoToNextChange,
15242        window: &mut Window,
15243        cx: &mut Context<Self>,
15244    ) {
15245        if let Some(selections) = self
15246            .change_list
15247            .next_change(1, Direction::Next)
15248            .map(|s| s.to_vec())
15249        {
15250            self.change_selections(Default::default(), window, cx, |s| {
15251                let map = s.display_map();
15252                s.select_display_ranges(selections.iter().map(|a| {
15253                    let point = a.to_display_point(&map);
15254                    point..point
15255                }))
15256            })
15257        }
15258    }
15259
15260    fn go_to_previous_change(
15261        &mut self,
15262        _: &GoToPreviousChange,
15263        window: &mut Window,
15264        cx: &mut Context<Self>,
15265    ) {
15266        if let Some(selections) = self
15267            .change_list
15268            .next_change(1, Direction::Prev)
15269            .map(|s| s.to_vec())
15270        {
15271            self.change_selections(Default::default(), window, cx, |s| {
15272                let map = s.display_map();
15273                s.select_display_ranges(selections.iter().map(|a| {
15274                    let point = a.to_display_point(&map);
15275                    point..point
15276                }))
15277            })
15278        }
15279    }
15280
15281    fn go_to_line<T: 'static>(
15282        &mut self,
15283        position: Anchor,
15284        highlight_color: Option<Hsla>,
15285        window: &mut Window,
15286        cx: &mut Context<Self>,
15287    ) {
15288        let snapshot = self.snapshot(window, cx).display_snapshot;
15289        let position = position.to_point(&snapshot.buffer_snapshot);
15290        let start = snapshot
15291            .buffer_snapshot
15292            .clip_point(Point::new(position.row, 0), Bias::Left);
15293        let end = start + Point::new(1, 0);
15294        let start = snapshot.buffer_snapshot.anchor_before(start);
15295        let end = snapshot.buffer_snapshot.anchor_before(end);
15296
15297        self.highlight_rows::<T>(
15298            start..end,
15299            highlight_color
15300                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15301            Default::default(),
15302            cx,
15303        );
15304
15305        if self.buffer.read(cx).is_singleton() {
15306            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15307        }
15308    }
15309
15310    pub fn go_to_definition(
15311        &mut self,
15312        _: &GoToDefinition,
15313        window: &mut Window,
15314        cx: &mut Context<Self>,
15315    ) -> Task<Result<Navigated>> {
15316        let definition =
15317            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15318        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15319        cx.spawn_in(window, async move |editor, cx| {
15320            if definition.await? == Navigated::Yes {
15321                return Ok(Navigated::Yes);
15322            }
15323            match fallback_strategy {
15324                GoToDefinitionFallback::None => Ok(Navigated::No),
15325                GoToDefinitionFallback::FindAllReferences => {
15326                    match editor.update_in(cx, |editor, window, cx| {
15327                        editor.find_all_references(&FindAllReferences, window, cx)
15328                    })? {
15329                        Some(references) => references.await,
15330                        None => Ok(Navigated::No),
15331                    }
15332                }
15333            }
15334        })
15335    }
15336
15337    pub fn go_to_declaration(
15338        &mut self,
15339        _: &GoToDeclaration,
15340        window: &mut Window,
15341        cx: &mut Context<Self>,
15342    ) -> Task<Result<Navigated>> {
15343        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15344    }
15345
15346    pub fn go_to_declaration_split(
15347        &mut self,
15348        _: &GoToDeclaration,
15349        window: &mut Window,
15350        cx: &mut Context<Self>,
15351    ) -> Task<Result<Navigated>> {
15352        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15353    }
15354
15355    pub fn go_to_implementation(
15356        &mut self,
15357        _: &GoToImplementation,
15358        window: &mut Window,
15359        cx: &mut Context<Self>,
15360    ) -> Task<Result<Navigated>> {
15361        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15362    }
15363
15364    pub fn go_to_implementation_split(
15365        &mut self,
15366        _: &GoToImplementationSplit,
15367        window: &mut Window,
15368        cx: &mut Context<Self>,
15369    ) -> Task<Result<Navigated>> {
15370        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15371    }
15372
15373    pub fn go_to_type_definition(
15374        &mut self,
15375        _: &GoToTypeDefinition,
15376        window: &mut Window,
15377        cx: &mut Context<Self>,
15378    ) -> Task<Result<Navigated>> {
15379        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15380    }
15381
15382    pub fn go_to_definition_split(
15383        &mut self,
15384        _: &GoToDefinitionSplit,
15385        window: &mut Window,
15386        cx: &mut Context<Self>,
15387    ) -> Task<Result<Navigated>> {
15388        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15389    }
15390
15391    pub fn go_to_type_definition_split(
15392        &mut self,
15393        _: &GoToTypeDefinitionSplit,
15394        window: &mut Window,
15395        cx: &mut Context<Self>,
15396    ) -> Task<Result<Navigated>> {
15397        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15398    }
15399
15400    fn go_to_definition_of_kind(
15401        &mut self,
15402        kind: GotoDefinitionKind,
15403        split: bool,
15404        window: &mut Window,
15405        cx: &mut Context<Self>,
15406    ) -> Task<Result<Navigated>> {
15407        let Some(provider) = self.semantics_provider.clone() else {
15408            return Task::ready(Ok(Navigated::No));
15409        };
15410        let head = self.selections.newest::<usize>(cx).head();
15411        let buffer = self.buffer.read(cx);
15412        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15413            text_anchor
15414        } else {
15415            return Task::ready(Ok(Navigated::No));
15416        };
15417
15418        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15419            return Task::ready(Ok(Navigated::No));
15420        };
15421
15422        cx.spawn_in(window, async move |editor, cx| {
15423            let definitions = definitions.await?;
15424            let navigated = editor
15425                .update_in(cx, |editor, window, cx| {
15426                    editor.navigate_to_hover_links(
15427                        Some(kind),
15428                        definitions
15429                            .into_iter()
15430                            .filter(|location| {
15431                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15432                            })
15433                            .map(HoverLink::Text)
15434                            .collect::<Vec<_>>(),
15435                        split,
15436                        window,
15437                        cx,
15438                    )
15439                })?
15440                .await?;
15441            anyhow::Ok(navigated)
15442        })
15443    }
15444
15445    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15446        let selection = self.selections.newest_anchor();
15447        let head = selection.head();
15448        let tail = selection.tail();
15449
15450        let Some((buffer, start_position)) =
15451            self.buffer.read(cx).text_anchor_for_position(head, cx)
15452        else {
15453            return;
15454        };
15455
15456        let end_position = if head != tail {
15457            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15458                return;
15459            };
15460            Some(pos)
15461        } else {
15462            None
15463        };
15464
15465        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15466            let url = if let Some(end_pos) = end_position {
15467                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15468            } else {
15469                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15470            };
15471
15472            if let Some(url) = url {
15473                editor.update(cx, |_, cx| {
15474                    cx.open_url(&url);
15475                })
15476            } else {
15477                Ok(())
15478            }
15479        });
15480
15481        url_finder.detach();
15482    }
15483
15484    pub fn open_selected_filename(
15485        &mut self,
15486        _: &OpenSelectedFilename,
15487        window: &mut Window,
15488        cx: &mut Context<Self>,
15489    ) {
15490        let Some(workspace) = self.workspace() else {
15491            return;
15492        };
15493
15494        let position = self.selections.newest_anchor().head();
15495
15496        let Some((buffer, buffer_position)) =
15497            self.buffer.read(cx).text_anchor_for_position(position, cx)
15498        else {
15499            return;
15500        };
15501
15502        let project = self.project.clone();
15503
15504        cx.spawn_in(window, async move |_, cx| {
15505            let result = find_file(&buffer, project, buffer_position, cx).await;
15506
15507            if let Some((_, path)) = result {
15508                workspace
15509                    .update_in(cx, |workspace, window, cx| {
15510                        workspace.open_resolved_path(path, window, cx)
15511                    })?
15512                    .await?;
15513            }
15514            anyhow::Ok(())
15515        })
15516        .detach();
15517    }
15518
15519    pub(crate) fn navigate_to_hover_links(
15520        &mut self,
15521        kind: Option<GotoDefinitionKind>,
15522        mut definitions: Vec<HoverLink>,
15523        split: bool,
15524        window: &mut Window,
15525        cx: &mut Context<Editor>,
15526    ) -> Task<Result<Navigated>> {
15527        // If there is one definition, just open it directly
15528        if definitions.len() == 1 {
15529            let definition = definitions.pop().unwrap();
15530
15531            enum TargetTaskResult {
15532                Location(Option<Location>),
15533                AlreadyNavigated,
15534            }
15535
15536            let target_task = match definition {
15537                HoverLink::Text(link) => {
15538                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15539                }
15540                HoverLink::InlayHint(lsp_location, server_id) => {
15541                    let computation =
15542                        self.compute_target_location(lsp_location, server_id, window, cx);
15543                    cx.background_spawn(async move {
15544                        let location = computation.await?;
15545                        Ok(TargetTaskResult::Location(location))
15546                    })
15547                }
15548                HoverLink::Url(url) => {
15549                    cx.open_url(&url);
15550                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15551                }
15552                HoverLink::File(path) => {
15553                    if let Some(workspace) = self.workspace() {
15554                        cx.spawn_in(window, async move |_, cx| {
15555                            workspace
15556                                .update_in(cx, |workspace, window, cx| {
15557                                    workspace.open_resolved_path(path, window, cx)
15558                                })?
15559                                .await
15560                                .map(|_| TargetTaskResult::AlreadyNavigated)
15561                        })
15562                    } else {
15563                        Task::ready(Ok(TargetTaskResult::Location(None)))
15564                    }
15565                }
15566            };
15567            cx.spawn_in(window, async move |editor, cx| {
15568                let target = match target_task.await.context("target resolution task")? {
15569                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15570                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15571                    TargetTaskResult::Location(Some(target)) => target,
15572                };
15573
15574                editor.update_in(cx, |editor, window, cx| {
15575                    let Some(workspace) = editor.workspace() else {
15576                        return Navigated::No;
15577                    };
15578                    let pane = workspace.read(cx).active_pane().clone();
15579
15580                    let range = target.range.to_point(target.buffer.read(cx));
15581                    let range = editor.range_for_match(&range);
15582                    let range = collapse_multiline_range(range);
15583
15584                    if !split
15585                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15586                    {
15587                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15588                    } else {
15589                        window.defer(cx, move |window, cx| {
15590                            let target_editor: Entity<Self> =
15591                                workspace.update(cx, |workspace, cx| {
15592                                    let pane = if split {
15593                                        workspace.adjacent_pane(window, cx)
15594                                    } else {
15595                                        workspace.active_pane().clone()
15596                                    };
15597
15598                                    workspace.open_project_item(
15599                                        pane,
15600                                        target.buffer.clone(),
15601                                        true,
15602                                        true,
15603                                        window,
15604                                        cx,
15605                                    )
15606                                });
15607                            target_editor.update(cx, |target_editor, cx| {
15608                                // When selecting a definition in a different buffer, disable the nav history
15609                                // to avoid creating a history entry at the previous cursor location.
15610                                pane.update(cx, |pane, _| pane.disable_history());
15611                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15612                                pane.update(cx, |pane, _| pane.enable_history());
15613                            });
15614                        });
15615                    }
15616                    Navigated::Yes
15617                })
15618            })
15619        } else if !definitions.is_empty() {
15620            cx.spawn_in(window, async move |editor, cx| {
15621                let (title, location_tasks, workspace) = editor
15622                    .update_in(cx, |editor, window, cx| {
15623                        let tab_kind = match kind {
15624                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15625                            _ => "Definitions",
15626                        };
15627                        let title = definitions
15628                            .iter()
15629                            .find_map(|definition| match definition {
15630                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15631                                    let buffer = origin.buffer.read(cx);
15632                                    format!(
15633                                        "{} for {}",
15634                                        tab_kind,
15635                                        buffer
15636                                            .text_for_range(origin.range.clone())
15637                                            .collect::<String>()
15638                                    )
15639                                }),
15640                                HoverLink::InlayHint(_, _) => None,
15641                                HoverLink::Url(_) => None,
15642                                HoverLink::File(_) => None,
15643                            })
15644                            .unwrap_or(tab_kind.to_string());
15645                        let location_tasks = definitions
15646                            .into_iter()
15647                            .map(|definition| match definition {
15648                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15649                                HoverLink::InlayHint(lsp_location, server_id) => editor
15650                                    .compute_target_location(lsp_location, server_id, window, cx),
15651                                HoverLink::Url(_) => Task::ready(Ok(None)),
15652                                HoverLink::File(_) => Task::ready(Ok(None)),
15653                            })
15654                            .collect::<Vec<_>>();
15655                        (title, location_tasks, editor.workspace().clone())
15656                    })
15657                    .context("location tasks preparation")?;
15658
15659                let locations: Vec<Location> = future::join_all(location_tasks)
15660                    .await
15661                    .into_iter()
15662                    .filter_map(|location| location.transpose())
15663                    .collect::<Result<_>>()
15664                    .context("location tasks")?;
15665
15666                if locations.is_empty() {
15667                    return Ok(Navigated::No);
15668                }
15669
15670                let Some(workspace) = workspace else {
15671                    return Ok(Navigated::No);
15672                };
15673
15674                let opened = workspace
15675                    .update_in(cx, |workspace, window, cx| {
15676                        Self::open_locations_in_multibuffer(
15677                            workspace,
15678                            locations,
15679                            title,
15680                            split,
15681                            MultibufferSelectionMode::First,
15682                            window,
15683                            cx,
15684                        )
15685                    })
15686                    .ok();
15687
15688                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15689            })
15690        } else {
15691            Task::ready(Ok(Navigated::No))
15692        }
15693    }
15694
15695    fn compute_target_location(
15696        &self,
15697        lsp_location: lsp::Location,
15698        server_id: LanguageServerId,
15699        window: &mut Window,
15700        cx: &mut Context<Self>,
15701    ) -> Task<anyhow::Result<Option<Location>>> {
15702        let Some(project) = self.project.clone() else {
15703            return Task::ready(Ok(None));
15704        };
15705
15706        cx.spawn_in(window, async move |editor, cx| {
15707            let location_task = editor.update(cx, |_, cx| {
15708                project.update(cx, |project, cx| {
15709                    let language_server_name = project
15710                        .language_server_statuses(cx)
15711                        .find(|(id, _)| server_id == *id)
15712                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15713                    language_server_name.map(|language_server_name| {
15714                        project.open_local_buffer_via_lsp(
15715                            lsp_location.uri.clone(),
15716                            server_id,
15717                            language_server_name,
15718                            cx,
15719                        )
15720                    })
15721                })
15722            })?;
15723            let location = match location_task {
15724                Some(task) => Some({
15725                    let target_buffer_handle = task.await.context("open local buffer")?;
15726                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15727                        let target_start = target_buffer
15728                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15729                        let target_end = target_buffer
15730                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15731                        target_buffer.anchor_after(target_start)
15732                            ..target_buffer.anchor_before(target_end)
15733                    })?;
15734                    Location {
15735                        buffer: target_buffer_handle,
15736                        range,
15737                    }
15738                }),
15739                None => None,
15740            };
15741            Ok(location)
15742        })
15743    }
15744
15745    pub fn find_all_references(
15746        &mut self,
15747        _: &FindAllReferences,
15748        window: &mut Window,
15749        cx: &mut Context<Self>,
15750    ) -> Option<Task<Result<Navigated>>> {
15751        let selection = self.selections.newest::<usize>(cx);
15752        let multi_buffer = self.buffer.read(cx);
15753        let head = selection.head();
15754
15755        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15756        let head_anchor = multi_buffer_snapshot.anchor_at(
15757            head,
15758            if head < selection.tail() {
15759                Bias::Right
15760            } else {
15761                Bias::Left
15762            },
15763        );
15764
15765        match self
15766            .find_all_references_task_sources
15767            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15768        {
15769            Ok(_) => {
15770                log::info!(
15771                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15772                );
15773                return None;
15774            }
15775            Err(i) => {
15776                self.find_all_references_task_sources.insert(i, head_anchor);
15777            }
15778        }
15779
15780        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15781        let workspace = self.workspace()?;
15782        let project = workspace.read(cx).project().clone();
15783        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15784        Some(cx.spawn_in(window, async move |editor, cx| {
15785            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15786                if let Ok(i) = editor
15787                    .find_all_references_task_sources
15788                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15789                {
15790                    editor.find_all_references_task_sources.remove(i);
15791                }
15792            });
15793
15794            let locations = references.await?;
15795            if locations.is_empty() {
15796                return anyhow::Ok(Navigated::No);
15797            }
15798
15799            workspace.update_in(cx, |workspace, window, cx| {
15800                let title = locations
15801                    .first()
15802                    .as_ref()
15803                    .map(|location| {
15804                        let buffer = location.buffer.read(cx);
15805                        format!(
15806                            "References to `{}`",
15807                            buffer
15808                                .text_for_range(location.range.clone())
15809                                .collect::<String>()
15810                        )
15811                    })
15812                    .unwrap();
15813                Self::open_locations_in_multibuffer(
15814                    workspace,
15815                    locations,
15816                    title,
15817                    false,
15818                    MultibufferSelectionMode::First,
15819                    window,
15820                    cx,
15821                );
15822                Navigated::Yes
15823            })
15824        }))
15825    }
15826
15827    /// Opens a multibuffer with the given project locations in it
15828    pub fn open_locations_in_multibuffer(
15829        workspace: &mut Workspace,
15830        mut locations: Vec<Location>,
15831        title: String,
15832        split: bool,
15833        multibuffer_selection_mode: MultibufferSelectionMode,
15834        window: &mut Window,
15835        cx: &mut Context<Workspace>,
15836    ) {
15837        if locations.is_empty() {
15838            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15839            return;
15840        }
15841
15842        // If there are multiple definitions, open them in a multibuffer
15843        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15844        let mut locations = locations.into_iter().peekable();
15845        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15846        let capability = workspace.project().read(cx).capability();
15847
15848        let excerpt_buffer = cx.new(|cx| {
15849            let mut multibuffer = MultiBuffer::new(capability);
15850            while let Some(location) = locations.next() {
15851                let buffer = location.buffer.read(cx);
15852                let mut ranges_for_buffer = Vec::new();
15853                let range = location.range.to_point(buffer);
15854                ranges_for_buffer.push(range.clone());
15855
15856                while let Some(next_location) = locations.peek() {
15857                    if next_location.buffer == location.buffer {
15858                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15859                        locations.next();
15860                    } else {
15861                        break;
15862                    }
15863                }
15864
15865                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15866                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15867                    PathKey::for_buffer(&location.buffer, cx),
15868                    location.buffer.clone(),
15869                    ranges_for_buffer,
15870                    DEFAULT_MULTIBUFFER_CONTEXT,
15871                    cx,
15872                );
15873                ranges.extend(new_ranges)
15874            }
15875
15876            multibuffer.with_title(title)
15877        });
15878
15879        let editor = cx.new(|cx| {
15880            Editor::for_multibuffer(
15881                excerpt_buffer,
15882                Some(workspace.project().clone()),
15883                window,
15884                cx,
15885            )
15886        });
15887        editor.update(cx, |editor, cx| {
15888            match multibuffer_selection_mode {
15889                MultibufferSelectionMode::First => {
15890                    if let Some(first_range) = ranges.first() {
15891                        editor.change_selections(
15892                            SelectionEffects::no_scroll(),
15893                            window,
15894                            cx,
15895                            |selections| {
15896                                selections.clear_disjoint();
15897                                selections
15898                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15899                            },
15900                        );
15901                    }
15902                    editor.highlight_background::<Self>(
15903                        &ranges,
15904                        |theme| theme.colors().editor_highlighted_line_background,
15905                        cx,
15906                    );
15907                }
15908                MultibufferSelectionMode::All => {
15909                    editor.change_selections(
15910                        SelectionEffects::no_scroll(),
15911                        window,
15912                        cx,
15913                        |selections| {
15914                            selections.clear_disjoint();
15915                            selections.select_anchor_ranges(ranges);
15916                        },
15917                    );
15918                }
15919            }
15920            editor.register_buffers_with_language_servers(cx);
15921        });
15922
15923        let item = Box::new(editor);
15924        let item_id = item.item_id();
15925
15926        if split {
15927            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15928        } else {
15929            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15930                let (preview_item_id, preview_item_idx) =
15931                    workspace.active_pane().read_with(cx, |pane, _| {
15932                        (pane.preview_item_id(), pane.preview_item_idx())
15933                    });
15934
15935                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15936
15937                if let Some(preview_item_id) = preview_item_id {
15938                    workspace.active_pane().update(cx, |pane, cx| {
15939                        pane.remove_item(preview_item_id, false, false, window, cx);
15940                    });
15941                }
15942            } else {
15943                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15944            }
15945        }
15946        workspace.active_pane().update(cx, |pane, cx| {
15947            pane.set_preview_item_id(Some(item_id), cx);
15948        });
15949    }
15950
15951    pub fn rename(
15952        &mut self,
15953        _: &Rename,
15954        window: &mut Window,
15955        cx: &mut Context<Self>,
15956    ) -> Option<Task<Result<()>>> {
15957        use language::ToOffset as _;
15958
15959        let provider = self.semantics_provider.clone()?;
15960        let selection = self.selections.newest_anchor().clone();
15961        let (cursor_buffer, cursor_buffer_position) = self
15962            .buffer
15963            .read(cx)
15964            .text_anchor_for_position(selection.head(), cx)?;
15965        let (tail_buffer, cursor_buffer_position_end) = self
15966            .buffer
15967            .read(cx)
15968            .text_anchor_for_position(selection.tail(), cx)?;
15969        if tail_buffer != cursor_buffer {
15970            return None;
15971        }
15972
15973        let snapshot = cursor_buffer.read(cx).snapshot();
15974        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15975        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15976        let prepare_rename = provider
15977            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15978            .unwrap_or_else(|| Task::ready(Ok(None)));
15979        drop(snapshot);
15980
15981        Some(cx.spawn_in(window, async move |this, cx| {
15982            let rename_range = if let Some(range) = prepare_rename.await? {
15983                Some(range)
15984            } else {
15985                this.update(cx, |this, cx| {
15986                    let buffer = this.buffer.read(cx).snapshot(cx);
15987                    let mut buffer_highlights = this
15988                        .document_highlights_for_position(selection.head(), &buffer)
15989                        .filter(|highlight| {
15990                            highlight.start.excerpt_id == selection.head().excerpt_id
15991                                && highlight.end.excerpt_id == selection.head().excerpt_id
15992                        });
15993                    buffer_highlights
15994                        .next()
15995                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15996                })?
15997            };
15998            if let Some(rename_range) = rename_range {
15999                this.update_in(cx, |this, window, cx| {
16000                    let snapshot = cursor_buffer.read(cx).snapshot();
16001                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16002                    let cursor_offset_in_rename_range =
16003                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16004                    let cursor_offset_in_rename_range_end =
16005                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16006
16007                    this.take_rename(false, window, cx);
16008                    let buffer = this.buffer.read(cx).read(cx);
16009                    let cursor_offset = selection.head().to_offset(&buffer);
16010                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16011                    let rename_end = rename_start + rename_buffer_range.len();
16012                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16013                    let mut old_highlight_id = None;
16014                    let old_name: Arc<str> = buffer
16015                        .chunks(rename_start..rename_end, true)
16016                        .map(|chunk| {
16017                            if old_highlight_id.is_none() {
16018                                old_highlight_id = chunk.syntax_highlight_id;
16019                            }
16020                            chunk.text
16021                        })
16022                        .collect::<String>()
16023                        .into();
16024
16025                    drop(buffer);
16026
16027                    // Position the selection in the rename editor so that it matches the current selection.
16028                    this.show_local_selections = false;
16029                    let rename_editor = cx.new(|cx| {
16030                        let mut editor = Editor::single_line(window, cx);
16031                        editor.buffer.update(cx, |buffer, cx| {
16032                            buffer.edit([(0..0, old_name.clone())], None, cx)
16033                        });
16034                        let rename_selection_range = match cursor_offset_in_rename_range
16035                            .cmp(&cursor_offset_in_rename_range_end)
16036                        {
16037                            Ordering::Equal => {
16038                                editor.select_all(&SelectAll, window, cx);
16039                                return editor;
16040                            }
16041                            Ordering::Less => {
16042                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16043                            }
16044                            Ordering::Greater => {
16045                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16046                            }
16047                        };
16048                        if rename_selection_range.end > old_name.len() {
16049                            editor.select_all(&SelectAll, window, cx);
16050                        } else {
16051                            editor.change_selections(Default::default(), window, cx, |s| {
16052                                s.select_ranges([rename_selection_range]);
16053                            });
16054                        }
16055                        editor
16056                    });
16057                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16058                        if e == &EditorEvent::Focused {
16059                            cx.emit(EditorEvent::FocusedIn)
16060                        }
16061                    })
16062                    .detach();
16063
16064                    let write_highlights =
16065                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16066                    let read_highlights =
16067                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16068                    let ranges = write_highlights
16069                        .iter()
16070                        .flat_map(|(_, ranges)| ranges.iter())
16071                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16072                        .cloned()
16073                        .collect();
16074
16075                    this.highlight_text::<Rename>(
16076                        ranges,
16077                        HighlightStyle {
16078                            fade_out: Some(0.6),
16079                            ..Default::default()
16080                        },
16081                        cx,
16082                    );
16083                    let rename_focus_handle = rename_editor.focus_handle(cx);
16084                    window.focus(&rename_focus_handle);
16085                    let block_id = this.insert_blocks(
16086                        [BlockProperties {
16087                            style: BlockStyle::Flex,
16088                            placement: BlockPlacement::Below(range.start),
16089                            height: Some(1),
16090                            render: Arc::new({
16091                                let rename_editor = rename_editor.clone();
16092                                move |cx: &mut BlockContext| {
16093                                    let mut text_style = cx.editor_style.text.clone();
16094                                    if let Some(highlight_style) = old_highlight_id
16095                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16096                                    {
16097                                        text_style = text_style.highlight(highlight_style);
16098                                    }
16099                                    div()
16100                                        .block_mouse_except_scroll()
16101                                        .pl(cx.anchor_x)
16102                                        .child(EditorElement::new(
16103                                            &rename_editor,
16104                                            EditorStyle {
16105                                                background: cx.theme().system().transparent,
16106                                                local_player: cx.editor_style.local_player,
16107                                                text: text_style,
16108                                                scrollbar_width: cx.editor_style.scrollbar_width,
16109                                                syntax: cx.editor_style.syntax.clone(),
16110                                                status: cx.editor_style.status.clone(),
16111                                                inlay_hints_style: HighlightStyle {
16112                                                    font_weight: Some(FontWeight::BOLD),
16113                                                    ..make_inlay_hints_style(cx.app)
16114                                                },
16115                                                inline_completion_styles: make_suggestion_styles(
16116                                                    cx.app,
16117                                                ),
16118                                                ..EditorStyle::default()
16119                                            },
16120                                        ))
16121                                        .into_any_element()
16122                                }
16123                            }),
16124                            priority: 0,
16125                            render_in_minimap: true,
16126                        }],
16127                        Some(Autoscroll::fit()),
16128                        cx,
16129                    )[0];
16130                    this.pending_rename = Some(RenameState {
16131                        range,
16132                        old_name,
16133                        editor: rename_editor,
16134                        block_id,
16135                    });
16136                })?;
16137            }
16138
16139            Ok(())
16140        }))
16141    }
16142
16143    pub fn confirm_rename(
16144        &mut self,
16145        _: &ConfirmRename,
16146        window: &mut Window,
16147        cx: &mut Context<Self>,
16148    ) -> Option<Task<Result<()>>> {
16149        let rename = self.take_rename(false, window, cx)?;
16150        let workspace = self.workspace()?.downgrade();
16151        let (buffer, start) = self
16152            .buffer
16153            .read(cx)
16154            .text_anchor_for_position(rename.range.start, cx)?;
16155        let (end_buffer, _) = self
16156            .buffer
16157            .read(cx)
16158            .text_anchor_for_position(rename.range.end, cx)?;
16159        if buffer != end_buffer {
16160            return None;
16161        }
16162
16163        let old_name = rename.old_name;
16164        let new_name = rename.editor.read(cx).text(cx);
16165
16166        let rename = self.semantics_provider.as_ref()?.perform_rename(
16167            &buffer,
16168            start,
16169            new_name.clone(),
16170            cx,
16171        )?;
16172
16173        Some(cx.spawn_in(window, async move |editor, cx| {
16174            let project_transaction = rename.await?;
16175            Self::open_project_transaction(
16176                &editor,
16177                workspace,
16178                project_transaction,
16179                format!("Rename: {}{}", old_name, new_name),
16180                cx,
16181            )
16182            .await?;
16183
16184            editor.update(cx, |editor, cx| {
16185                editor.refresh_document_highlights(cx);
16186            })?;
16187            Ok(())
16188        }))
16189    }
16190
16191    fn take_rename(
16192        &mut self,
16193        moving_cursor: bool,
16194        window: &mut Window,
16195        cx: &mut Context<Self>,
16196    ) -> Option<RenameState> {
16197        let rename = self.pending_rename.take()?;
16198        if rename.editor.focus_handle(cx).is_focused(window) {
16199            window.focus(&self.focus_handle);
16200        }
16201
16202        self.remove_blocks(
16203            [rename.block_id].into_iter().collect(),
16204            Some(Autoscroll::fit()),
16205            cx,
16206        );
16207        self.clear_highlights::<Rename>(cx);
16208        self.show_local_selections = true;
16209
16210        if moving_cursor {
16211            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16212                editor.selections.newest::<usize>(cx).head()
16213            });
16214
16215            // Update the selection to match the position of the selection inside
16216            // the rename editor.
16217            let snapshot = self.buffer.read(cx).read(cx);
16218            let rename_range = rename.range.to_offset(&snapshot);
16219            let cursor_in_editor = snapshot
16220                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16221                .min(rename_range.end);
16222            drop(snapshot);
16223
16224            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16225                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16226            });
16227        } else {
16228            self.refresh_document_highlights(cx);
16229        }
16230
16231        Some(rename)
16232    }
16233
16234    pub fn pending_rename(&self) -> Option<&RenameState> {
16235        self.pending_rename.as_ref()
16236    }
16237
16238    fn format(
16239        &mut self,
16240        _: &Format,
16241        window: &mut Window,
16242        cx: &mut Context<Self>,
16243    ) -> Option<Task<Result<()>>> {
16244        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16245
16246        let project = match &self.project {
16247            Some(project) => project.clone(),
16248            None => return None,
16249        };
16250
16251        Some(self.perform_format(
16252            project,
16253            FormatTrigger::Manual,
16254            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16255            window,
16256            cx,
16257        ))
16258    }
16259
16260    fn format_selections(
16261        &mut self,
16262        _: &FormatSelections,
16263        window: &mut Window,
16264        cx: &mut Context<Self>,
16265    ) -> Option<Task<Result<()>>> {
16266        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16267
16268        let project = match &self.project {
16269            Some(project) => project.clone(),
16270            None => return None,
16271        };
16272
16273        let ranges = self
16274            .selections
16275            .all_adjusted(cx)
16276            .into_iter()
16277            .map(|selection| selection.range())
16278            .collect_vec();
16279
16280        Some(self.perform_format(
16281            project,
16282            FormatTrigger::Manual,
16283            FormatTarget::Ranges(ranges),
16284            window,
16285            cx,
16286        ))
16287    }
16288
16289    fn perform_format(
16290        &mut self,
16291        project: Entity<Project>,
16292        trigger: FormatTrigger,
16293        target: FormatTarget,
16294        window: &mut Window,
16295        cx: &mut Context<Self>,
16296    ) -> Task<Result<()>> {
16297        let buffer = self.buffer.clone();
16298        let (buffers, target) = match target {
16299            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16300            FormatTarget::Ranges(selection_ranges) => {
16301                let multi_buffer = buffer.read(cx);
16302                let snapshot = multi_buffer.read(cx);
16303                let mut buffers = HashSet::default();
16304                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16305                    BTreeMap::new();
16306                for selection_range in selection_ranges {
16307                    for (buffer, buffer_range, _) in
16308                        snapshot.range_to_buffer_ranges(selection_range)
16309                    {
16310                        let buffer_id = buffer.remote_id();
16311                        let start = buffer.anchor_before(buffer_range.start);
16312                        let end = buffer.anchor_after(buffer_range.end);
16313                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16314                        buffer_id_to_ranges
16315                            .entry(buffer_id)
16316                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16317                            .or_insert_with(|| vec![start..end]);
16318                    }
16319                }
16320                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16321            }
16322        };
16323
16324        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16325        let selections_prev = transaction_id_prev
16326            .and_then(|transaction_id_prev| {
16327                // default to selections as they were after the last edit, if we have them,
16328                // instead of how they are now.
16329                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16330                // will take you back to where you made the last edit, instead of staying where you scrolled
16331                self.selection_history
16332                    .transaction(transaction_id_prev)
16333                    .map(|t| t.0.clone())
16334            })
16335            .unwrap_or_else(|| {
16336                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16337                self.selections.disjoint_anchors()
16338            });
16339
16340        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16341        let format = project.update(cx, |project, cx| {
16342            project.format(buffers, target, true, trigger, cx)
16343        });
16344
16345        cx.spawn_in(window, async move |editor, cx| {
16346            let transaction = futures::select_biased! {
16347                transaction = format.log_err().fuse() => transaction,
16348                () = timeout => {
16349                    log::warn!("timed out waiting for formatting");
16350                    None
16351                }
16352            };
16353
16354            buffer
16355                .update(cx, |buffer, cx| {
16356                    if let Some(transaction) = transaction {
16357                        if !buffer.is_singleton() {
16358                            buffer.push_transaction(&transaction.0, cx);
16359                        }
16360                    }
16361                    cx.notify();
16362                })
16363                .ok();
16364
16365            if let Some(transaction_id_now) =
16366                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16367            {
16368                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16369                if has_new_transaction {
16370                    _ = editor.update(cx, |editor, _| {
16371                        editor
16372                            .selection_history
16373                            .insert_transaction(transaction_id_now, selections_prev);
16374                    });
16375                }
16376            }
16377
16378            Ok(())
16379        })
16380    }
16381
16382    fn organize_imports(
16383        &mut self,
16384        _: &OrganizeImports,
16385        window: &mut Window,
16386        cx: &mut Context<Self>,
16387    ) -> Option<Task<Result<()>>> {
16388        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16389        let project = match &self.project {
16390            Some(project) => project.clone(),
16391            None => return None,
16392        };
16393        Some(self.perform_code_action_kind(
16394            project,
16395            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16396            window,
16397            cx,
16398        ))
16399    }
16400
16401    fn perform_code_action_kind(
16402        &mut self,
16403        project: Entity<Project>,
16404        kind: CodeActionKind,
16405        window: &mut Window,
16406        cx: &mut Context<Self>,
16407    ) -> Task<Result<()>> {
16408        let buffer = self.buffer.clone();
16409        let buffers = buffer.read(cx).all_buffers();
16410        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16411        let apply_action = project.update(cx, |project, cx| {
16412            project.apply_code_action_kind(buffers, kind, true, cx)
16413        });
16414        cx.spawn_in(window, async move |_, cx| {
16415            let transaction = futures::select_biased! {
16416                () = timeout => {
16417                    log::warn!("timed out waiting for executing code action");
16418                    None
16419                }
16420                transaction = apply_action.log_err().fuse() => transaction,
16421            };
16422            buffer
16423                .update(cx, |buffer, cx| {
16424                    // check if we need this
16425                    if let Some(transaction) = transaction {
16426                        if !buffer.is_singleton() {
16427                            buffer.push_transaction(&transaction.0, cx);
16428                        }
16429                    }
16430                    cx.notify();
16431                })
16432                .ok();
16433            Ok(())
16434        })
16435    }
16436
16437    pub fn restart_language_server(
16438        &mut self,
16439        _: &RestartLanguageServer,
16440        _: &mut Window,
16441        cx: &mut Context<Self>,
16442    ) {
16443        if let Some(project) = self.project.clone() {
16444            self.buffer.update(cx, |multi_buffer, cx| {
16445                project.update(cx, |project, cx| {
16446                    project.restart_language_servers_for_buffers(
16447                        multi_buffer.all_buffers().into_iter().collect(),
16448                        HashSet::default(),
16449                        cx,
16450                    );
16451                });
16452            })
16453        }
16454    }
16455
16456    pub fn stop_language_server(
16457        &mut self,
16458        _: &StopLanguageServer,
16459        _: &mut Window,
16460        cx: &mut Context<Self>,
16461    ) {
16462        if let Some(project) = self.project.clone() {
16463            self.buffer.update(cx, |multi_buffer, cx| {
16464                project.update(cx, |project, cx| {
16465                    project.stop_language_servers_for_buffers(
16466                        multi_buffer.all_buffers().into_iter().collect(),
16467                        HashSet::default(),
16468                        cx,
16469                    );
16470                    cx.emit(project::Event::RefreshInlayHints);
16471                });
16472            });
16473        }
16474    }
16475
16476    fn cancel_language_server_work(
16477        workspace: &mut Workspace,
16478        _: &actions::CancelLanguageServerWork,
16479        _: &mut Window,
16480        cx: &mut Context<Workspace>,
16481    ) {
16482        let project = workspace.project();
16483        let buffers = workspace
16484            .active_item(cx)
16485            .and_then(|item| item.act_as::<Editor>(cx))
16486            .map_or(HashSet::default(), |editor| {
16487                editor.read(cx).buffer.read(cx).all_buffers()
16488            });
16489        project.update(cx, |project, cx| {
16490            project.cancel_language_server_work_for_buffers(buffers, cx);
16491        });
16492    }
16493
16494    fn show_character_palette(
16495        &mut self,
16496        _: &ShowCharacterPalette,
16497        window: &mut Window,
16498        _: &mut Context<Self>,
16499    ) {
16500        window.show_character_palette();
16501    }
16502
16503    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16504        if !self.diagnostics_enabled() {
16505            return;
16506        }
16507
16508        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16509            let buffer = self.buffer.read(cx).snapshot(cx);
16510            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16511            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16512            let is_valid = buffer
16513                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16514                .any(|entry| {
16515                    entry.diagnostic.is_primary
16516                        && !entry.range.is_empty()
16517                        && entry.range.start == primary_range_start
16518                        && entry.diagnostic.message == active_diagnostics.active_message
16519                });
16520
16521            if !is_valid {
16522                self.dismiss_diagnostics(cx);
16523            }
16524        }
16525    }
16526
16527    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16528        match &self.active_diagnostics {
16529            ActiveDiagnostic::Group(group) => Some(group),
16530            _ => None,
16531        }
16532    }
16533
16534    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16535        if !self.diagnostics_enabled() {
16536            return;
16537        }
16538        self.dismiss_diagnostics(cx);
16539        self.active_diagnostics = ActiveDiagnostic::All;
16540    }
16541
16542    fn activate_diagnostics(
16543        &mut self,
16544        buffer_id: BufferId,
16545        diagnostic: DiagnosticEntry<usize>,
16546        window: &mut Window,
16547        cx: &mut Context<Self>,
16548    ) {
16549        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16550            return;
16551        }
16552        self.dismiss_diagnostics(cx);
16553        let snapshot = self.snapshot(window, cx);
16554        let buffer = self.buffer.read(cx).snapshot(cx);
16555        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16556            return;
16557        };
16558
16559        let diagnostic_group = buffer
16560            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16561            .collect::<Vec<_>>();
16562
16563        let blocks =
16564            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16565
16566        let blocks = self.display_map.update(cx, |display_map, cx| {
16567            display_map.insert_blocks(blocks, cx).into_iter().collect()
16568        });
16569        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16570            active_range: buffer.anchor_before(diagnostic.range.start)
16571                ..buffer.anchor_after(diagnostic.range.end),
16572            active_message: diagnostic.diagnostic.message.clone(),
16573            group_id: diagnostic.diagnostic.group_id,
16574            blocks,
16575        });
16576        cx.notify();
16577    }
16578
16579    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16580        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16581            return;
16582        };
16583
16584        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16585        if let ActiveDiagnostic::Group(group) = prev {
16586            self.display_map.update(cx, |display_map, cx| {
16587                display_map.remove_blocks(group.blocks, cx);
16588            });
16589            cx.notify();
16590        }
16591    }
16592
16593    /// Disable inline diagnostics rendering for this editor.
16594    pub fn disable_inline_diagnostics(&mut self) {
16595        self.inline_diagnostics_enabled = false;
16596        self.inline_diagnostics_update = Task::ready(());
16597        self.inline_diagnostics.clear();
16598    }
16599
16600    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16601        self.diagnostics_enabled = false;
16602        self.dismiss_diagnostics(cx);
16603        self.inline_diagnostics_update = Task::ready(());
16604        self.inline_diagnostics.clear();
16605    }
16606
16607    pub fn diagnostics_enabled(&self) -> bool {
16608        self.diagnostics_enabled && self.mode.is_full()
16609    }
16610
16611    pub fn inline_diagnostics_enabled(&self) -> bool {
16612        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16613    }
16614
16615    pub fn show_inline_diagnostics(&self) -> bool {
16616        self.show_inline_diagnostics
16617    }
16618
16619    pub fn toggle_inline_diagnostics(
16620        &mut self,
16621        _: &ToggleInlineDiagnostics,
16622        window: &mut Window,
16623        cx: &mut Context<Editor>,
16624    ) {
16625        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16626        self.refresh_inline_diagnostics(false, window, cx);
16627    }
16628
16629    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16630        self.diagnostics_max_severity = severity;
16631        self.display_map.update(cx, |display_map, _| {
16632            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16633        });
16634    }
16635
16636    pub fn toggle_diagnostics(
16637        &mut self,
16638        _: &ToggleDiagnostics,
16639        window: &mut Window,
16640        cx: &mut Context<Editor>,
16641    ) {
16642        if !self.diagnostics_enabled() {
16643            return;
16644        }
16645
16646        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16647            EditorSettings::get_global(cx)
16648                .diagnostics_max_severity
16649                .filter(|severity| severity != &DiagnosticSeverity::Off)
16650                .unwrap_or(DiagnosticSeverity::Hint)
16651        } else {
16652            DiagnosticSeverity::Off
16653        };
16654        self.set_max_diagnostics_severity(new_severity, cx);
16655        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16656            self.active_diagnostics = ActiveDiagnostic::None;
16657            self.inline_diagnostics_update = Task::ready(());
16658            self.inline_diagnostics.clear();
16659        } else {
16660            self.refresh_inline_diagnostics(false, window, cx);
16661        }
16662
16663        cx.notify();
16664    }
16665
16666    pub fn toggle_minimap(
16667        &mut self,
16668        _: &ToggleMinimap,
16669        window: &mut Window,
16670        cx: &mut Context<Editor>,
16671    ) {
16672        if self.supports_minimap(cx) {
16673            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16674        }
16675    }
16676
16677    fn refresh_inline_diagnostics(
16678        &mut self,
16679        debounce: bool,
16680        window: &mut Window,
16681        cx: &mut Context<Self>,
16682    ) {
16683        let max_severity = ProjectSettings::get_global(cx)
16684            .diagnostics
16685            .inline
16686            .max_severity
16687            .unwrap_or(self.diagnostics_max_severity);
16688
16689        if !self.inline_diagnostics_enabled()
16690            || !self.show_inline_diagnostics
16691            || max_severity == DiagnosticSeverity::Off
16692        {
16693            self.inline_diagnostics_update = Task::ready(());
16694            self.inline_diagnostics.clear();
16695            return;
16696        }
16697
16698        let debounce_ms = ProjectSettings::get_global(cx)
16699            .diagnostics
16700            .inline
16701            .update_debounce_ms;
16702        let debounce = if debounce && debounce_ms > 0 {
16703            Some(Duration::from_millis(debounce_ms))
16704        } else {
16705            None
16706        };
16707        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16708            if let Some(debounce) = debounce {
16709                cx.background_executor().timer(debounce).await;
16710            }
16711            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16712                editor
16713                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16714                    .ok()
16715            }) else {
16716                return;
16717            };
16718
16719            let new_inline_diagnostics = cx
16720                .background_spawn(async move {
16721                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16722                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16723                        let message = diagnostic_entry
16724                            .diagnostic
16725                            .message
16726                            .split_once('\n')
16727                            .map(|(line, _)| line)
16728                            .map(SharedString::new)
16729                            .unwrap_or_else(|| {
16730                                SharedString::from(diagnostic_entry.diagnostic.message)
16731                            });
16732                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16733                        let (Ok(i) | Err(i)) = inline_diagnostics
16734                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16735                        inline_diagnostics.insert(
16736                            i,
16737                            (
16738                                start_anchor,
16739                                InlineDiagnostic {
16740                                    message,
16741                                    group_id: diagnostic_entry.diagnostic.group_id,
16742                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16743                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16744                                    severity: diagnostic_entry.diagnostic.severity,
16745                                },
16746                            ),
16747                        );
16748                    }
16749                    inline_diagnostics
16750                })
16751                .await;
16752
16753            editor
16754                .update(cx, |editor, cx| {
16755                    editor.inline_diagnostics = new_inline_diagnostics;
16756                    cx.notify();
16757                })
16758                .ok();
16759        });
16760    }
16761
16762    fn pull_diagnostics(
16763        &mut self,
16764        buffer_id: Option<BufferId>,
16765        window: &Window,
16766        cx: &mut Context<Self>,
16767    ) -> Option<()> {
16768        if !self.mode().is_full() {
16769            return None;
16770        }
16771        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16772            .diagnostics
16773            .lsp_pull_diagnostics;
16774        if !pull_diagnostics_settings.enabled {
16775            return None;
16776        }
16777        let project = self.project.as_ref()?.downgrade();
16778        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16779        let mut buffers = self.buffer.read(cx).all_buffers();
16780        if let Some(buffer_id) = buffer_id {
16781            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16782        }
16783
16784        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16785            cx.background_executor().timer(debounce).await;
16786
16787            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16788                buffers
16789                    .into_iter()
16790                    .filter_map(|buffer| {
16791                        project
16792                            .update(cx, |project, cx| {
16793                                project.lsp_store().update(cx, |lsp_store, cx| {
16794                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16795                                })
16796                            })
16797                            .ok()
16798                    })
16799                    .collect::<FuturesUnordered<_>>()
16800            }) else {
16801                return;
16802            };
16803
16804            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16805                match pull_task {
16806                    Ok(()) => {
16807                        if editor
16808                            .update_in(cx, |editor, window, cx| {
16809                                editor.update_diagnostics_state(window, cx);
16810                            })
16811                            .is_err()
16812                        {
16813                            return;
16814                        }
16815                    }
16816                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16817                }
16818            }
16819        });
16820
16821        Some(())
16822    }
16823
16824    pub fn set_selections_from_remote(
16825        &mut self,
16826        selections: Vec<Selection<Anchor>>,
16827        pending_selection: Option<Selection<Anchor>>,
16828        window: &mut Window,
16829        cx: &mut Context<Self>,
16830    ) {
16831        let old_cursor_position = self.selections.newest_anchor().head();
16832        self.selections.change_with(cx, |s| {
16833            s.select_anchors(selections);
16834            if let Some(pending_selection) = pending_selection {
16835                s.set_pending(pending_selection, SelectMode::Character);
16836            } else {
16837                s.clear_pending();
16838            }
16839        });
16840        self.selections_did_change(
16841            false,
16842            &old_cursor_position,
16843            SelectionEffects::default(),
16844            window,
16845            cx,
16846        );
16847    }
16848
16849    pub fn transact(
16850        &mut self,
16851        window: &mut Window,
16852        cx: &mut Context<Self>,
16853        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16854    ) -> Option<TransactionId> {
16855        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16856            this.start_transaction_at(Instant::now(), window, cx);
16857            update(this, window, cx);
16858            this.end_transaction_at(Instant::now(), cx)
16859        })
16860    }
16861
16862    pub fn start_transaction_at(
16863        &mut self,
16864        now: Instant,
16865        window: &mut Window,
16866        cx: &mut Context<Self>,
16867    ) {
16868        self.end_selection(window, cx);
16869        if let Some(tx_id) = self
16870            .buffer
16871            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16872        {
16873            self.selection_history
16874                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16875            cx.emit(EditorEvent::TransactionBegun {
16876                transaction_id: tx_id,
16877            })
16878        }
16879    }
16880
16881    pub fn end_transaction_at(
16882        &mut self,
16883        now: Instant,
16884        cx: &mut Context<Self>,
16885    ) -> Option<TransactionId> {
16886        if let Some(transaction_id) = self
16887            .buffer
16888            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16889        {
16890            if let Some((_, end_selections)) =
16891                self.selection_history.transaction_mut(transaction_id)
16892            {
16893                *end_selections = Some(self.selections.disjoint_anchors());
16894            } else {
16895                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16896            }
16897
16898            cx.emit(EditorEvent::Edited { transaction_id });
16899            Some(transaction_id)
16900        } else {
16901            None
16902        }
16903    }
16904
16905    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16906        if self.selection_mark_mode {
16907            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16908                s.move_with(|_, sel| {
16909                    sel.collapse_to(sel.head(), SelectionGoal::None);
16910                });
16911            })
16912        }
16913        self.selection_mark_mode = true;
16914        cx.notify();
16915    }
16916
16917    pub fn swap_selection_ends(
16918        &mut self,
16919        _: &actions::SwapSelectionEnds,
16920        window: &mut Window,
16921        cx: &mut Context<Self>,
16922    ) {
16923        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16924            s.move_with(|_, sel| {
16925                if sel.start != sel.end {
16926                    sel.reversed = !sel.reversed
16927                }
16928            });
16929        });
16930        self.request_autoscroll(Autoscroll::newest(), cx);
16931        cx.notify();
16932    }
16933
16934    pub fn toggle_fold(
16935        &mut self,
16936        _: &actions::ToggleFold,
16937        window: &mut Window,
16938        cx: &mut Context<Self>,
16939    ) {
16940        if self.is_singleton(cx) {
16941            let selection = self.selections.newest::<Point>(cx);
16942
16943            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16944            let range = if selection.is_empty() {
16945                let point = selection.head().to_display_point(&display_map);
16946                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16947                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16948                    .to_point(&display_map);
16949                start..end
16950            } else {
16951                selection.range()
16952            };
16953            if display_map.folds_in_range(range).next().is_some() {
16954                self.unfold_lines(&Default::default(), window, cx)
16955            } else {
16956                self.fold(&Default::default(), window, cx)
16957            }
16958        } else {
16959            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16960            let buffer_ids: HashSet<_> = self
16961                .selections
16962                .disjoint_anchor_ranges()
16963                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16964                .collect();
16965
16966            let should_unfold = buffer_ids
16967                .iter()
16968                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16969
16970            for buffer_id in buffer_ids {
16971                if should_unfold {
16972                    self.unfold_buffer(buffer_id, cx);
16973                } else {
16974                    self.fold_buffer(buffer_id, cx);
16975                }
16976            }
16977        }
16978    }
16979
16980    pub fn toggle_fold_recursive(
16981        &mut self,
16982        _: &actions::ToggleFoldRecursive,
16983        window: &mut Window,
16984        cx: &mut Context<Self>,
16985    ) {
16986        let selection = self.selections.newest::<Point>(cx);
16987
16988        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16989        let range = if selection.is_empty() {
16990            let point = selection.head().to_display_point(&display_map);
16991            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16992            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16993                .to_point(&display_map);
16994            start..end
16995        } else {
16996            selection.range()
16997        };
16998        if display_map.folds_in_range(range).next().is_some() {
16999            self.unfold_recursive(&Default::default(), window, cx)
17000        } else {
17001            self.fold_recursive(&Default::default(), window, cx)
17002        }
17003    }
17004
17005    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17006        if self.is_singleton(cx) {
17007            let mut to_fold = Vec::new();
17008            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17009            let selections = self.selections.all_adjusted(cx);
17010
17011            for selection in selections {
17012                let range = selection.range().sorted();
17013                let buffer_start_row = range.start.row;
17014
17015                if range.start.row != range.end.row {
17016                    let mut found = false;
17017                    let mut row = range.start.row;
17018                    while row <= range.end.row {
17019                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17020                        {
17021                            found = true;
17022                            row = crease.range().end.row + 1;
17023                            to_fold.push(crease);
17024                        } else {
17025                            row += 1
17026                        }
17027                    }
17028                    if found {
17029                        continue;
17030                    }
17031                }
17032
17033                for row in (0..=range.start.row).rev() {
17034                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17035                        if crease.range().end.row >= buffer_start_row {
17036                            to_fold.push(crease);
17037                            if row <= range.start.row {
17038                                break;
17039                            }
17040                        }
17041                    }
17042                }
17043            }
17044
17045            self.fold_creases(to_fold, true, window, cx);
17046        } else {
17047            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17048            let buffer_ids = self
17049                .selections
17050                .disjoint_anchor_ranges()
17051                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17052                .collect::<HashSet<_>>();
17053            for buffer_id in buffer_ids {
17054                self.fold_buffer(buffer_id, cx);
17055            }
17056        }
17057    }
17058
17059    fn fold_at_level(
17060        &mut self,
17061        fold_at: &FoldAtLevel,
17062        window: &mut Window,
17063        cx: &mut Context<Self>,
17064    ) {
17065        if !self.buffer.read(cx).is_singleton() {
17066            return;
17067        }
17068
17069        let fold_at_level = fold_at.0;
17070        let snapshot = self.buffer.read(cx).snapshot(cx);
17071        let mut to_fold = Vec::new();
17072        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17073
17074        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17075            while start_row < end_row {
17076                match self
17077                    .snapshot(window, cx)
17078                    .crease_for_buffer_row(MultiBufferRow(start_row))
17079                {
17080                    Some(crease) => {
17081                        let nested_start_row = crease.range().start.row + 1;
17082                        let nested_end_row = crease.range().end.row;
17083
17084                        if current_level < fold_at_level {
17085                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17086                        } else if current_level == fold_at_level {
17087                            to_fold.push(crease);
17088                        }
17089
17090                        start_row = nested_end_row + 1;
17091                    }
17092                    None => start_row += 1,
17093                }
17094            }
17095        }
17096
17097        self.fold_creases(to_fold, true, window, cx);
17098    }
17099
17100    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17101        if self.buffer.read(cx).is_singleton() {
17102            let mut fold_ranges = Vec::new();
17103            let snapshot = self.buffer.read(cx).snapshot(cx);
17104
17105            for row in 0..snapshot.max_row().0 {
17106                if let Some(foldable_range) = self
17107                    .snapshot(window, cx)
17108                    .crease_for_buffer_row(MultiBufferRow(row))
17109                {
17110                    fold_ranges.push(foldable_range);
17111                }
17112            }
17113
17114            self.fold_creases(fold_ranges, true, window, cx);
17115        } else {
17116            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17117                editor
17118                    .update_in(cx, |editor, _, cx| {
17119                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17120                            editor.fold_buffer(buffer_id, cx);
17121                        }
17122                    })
17123                    .ok();
17124            });
17125        }
17126    }
17127
17128    pub fn fold_function_bodies(
17129        &mut self,
17130        _: &actions::FoldFunctionBodies,
17131        window: &mut Window,
17132        cx: &mut Context<Self>,
17133    ) {
17134        let snapshot = self.buffer.read(cx).snapshot(cx);
17135
17136        let ranges = snapshot
17137            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17138            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17139            .collect::<Vec<_>>();
17140
17141        let creases = ranges
17142            .into_iter()
17143            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17144            .collect();
17145
17146        self.fold_creases(creases, true, window, cx);
17147    }
17148
17149    pub fn fold_recursive(
17150        &mut self,
17151        _: &actions::FoldRecursive,
17152        window: &mut Window,
17153        cx: &mut Context<Self>,
17154    ) {
17155        let mut to_fold = Vec::new();
17156        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17157        let selections = self.selections.all_adjusted(cx);
17158
17159        for selection in selections {
17160            let range = selection.range().sorted();
17161            let buffer_start_row = range.start.row;
17162
17163            if range.start.row != range.end.row {
17164                let mut found = false;
17165                for row in range.start.row..=range.end.row {
17166                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17167                        found = true;
17168                        to_fold.push(crease);
17169                    }
17170                }
17171                if found {
17172                    continue;
17173                }
17174            }
17175
17176            for row in (0..=range.start.row).rev() {
17177                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17178                    if crease.range().end.row >= buffer_start_row {
17179                        to_fold.push(crease);
17180                    } else {
17181                        break;
17182                    }
17183                }
17184            }
17185        }
17186
17187        self.fold_creases(to_fold, true, window, cx);
17188    }
17189
17190    pub fn fold_at(
17191        &mut self,
17192        buffer_row: MultiBufferRow,
17193        window: &mut Window,
17194        cx: &mut Context<Self>,
17195    ) {
17196        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17197
17198        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17199            let autoscroll = self
17200                .selections
17201                .all::<Point>(cx)
17202                .iter()
17203                .any(|selection| crease.range().overlaps(&selection.range()));
17204
17205            self.fold_creases(vec![crease], autoscroll, window, cx);
17206        }
17207    }
17208
17209    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17210        if self.is_singleton(cx) {
17211            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17212            let buffer = &display_map.buffer_snapshot;
17213            let selections = self.selections.all::<Point>(cx);
17214            let ranges = selections
17215                .iter()
17216                .map(|s| {
17217                    let range = s.display_range(&display_map).sorted();
17218                    let mut start = range.start.to_point(&display_map);
17219                    let mut end = range.end.to_point(&display_map);
17220                    start.column = 0;
17221                    end.column = buffer.line_len(MultiBufferRow(end.row));
17222                    start..end
17223                })
17224                .collect::<Vec<_>>();
17225
17226            self.unfold_ranges(&ranges, true, true, cx);
17227        } else {
17228            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17229            let buffer_ids = self
17230                .selections
17231                .disjoint_anchor_ranges()
17232                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17233                .collect::<HashSet<_>>();
17234            for buffer_id in buffer_ids {
17235                self.unfold_buffer(buffer_id, cx);
17236            }
17237        }
17238    }
17239
17240    pub fn unfold_recursive(
17241        &mut self,
17242        _: &UnfoldRecursive,
17243        _window: &mut Window,
17244        cx: &mut Context<Self>,
17245    ) {
17246        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17247        let selections = self.selections.all::<Point>(cx);
17248        let ranges = selections
17249            .iter()
17250            .map(|s| {
17251                let mut range = s.display_range(&display_map).sorted();
17252                *range.start.column_mut() = 0;
17253                *range.end.column_mut() = display_map.line_len(range.end.row());
17254                let start = range.start.to_point(&display_map);
17255                let end = range.end.to_point(&display_map);
17256                start..end
17257            })
17258            .collect::<Vec<_>>();
17259
17260        self.unfold_ranges(&ranges, true, true, cx);
17261    }
17262
17263    pub fn unfold_at(
17264        &mut self,
17265        buffer_row: MultiBufferRow,
17266        _window: &mut Window,
17267        cx: &mut Context<Self>,
17268    ) {
17269        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17270
17271        let intersection_range = Point::new(buffer_row.0, 0)
17272            ..Point::new(
17273                buffer_row.0,
17274                display_map.buffer_snapshot.line_len(buffer_row),
17275            );
17276
17277        let autoscroll = self
17278            .selections
17279            .all::<Point>(cx)
17280            .iter()
17281            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17282
17283        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17284    }
17285
17286    pub fn unfold_all(
17287        &mut self,
17288        _: &actions::UnfoldAll,
17289        _window: &mut Window,
17290        cx: &mut Context<Self>,
17291    ) {
17292        if self.buffer.read(cx).is_singleton() {
17293            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17294            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17295        } else {
17296            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17297                editor
17298                    .update(cx, |editor, cx| {
17299                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17300                            editor.unfold_buffer(buffer_id, cx);
17301                        }
17302                    })
17303                    .ok();
17304            });
17305        }
17306    }
17307
17308    pub fn fold_selected_ranges(
17309        &mut self,
17310        _: &FoldSelectedRanges,
17311        window: &mut Window,
17312        cx: &mut Context<Self>,
17313    ) {
17314        let selections = self.selections.all_adjusted(cx);
17315        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17316        let ranges = selections
17317            .into_iter()
17318            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17319            .collect::<Vec<_>>();
17320        self.fold_creases(ranges, true, window, cx);
17321    }
17322
17323    pub fn fold_ranges<T: ToOffset + Clone>(
17324        &mut self,
17325        ranges: Vec<Range<T>>,
17326        auto_scroll: bool,
17327        window: &mut Window,
17328        cx: &mut Context<Self>,
17329    ) {
17330        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17331        let ranges = ranges
17332            .into_iter()
17333            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17334            .collect::<Vec<_>>();
17335        self.fold_creases(ranges, auto_scroll, window, cx);
17336    }
17337
17338    pub fn fold_creases<T: ToOffset + Clone>(
17339        &mut self,
17340        creases: Vec<Crease<T>>,
17341        auto_scroll: bool,
17342        _window: &mut Window,
17343        cx: &mut Context<Self>,
17344    ) {
17345        if creases.is_empty() {
17346            return;
17347        }
17348
17349        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17350
17351        if auto_scroll {
17352            self.request_autoscroll(Autoscroll::fit(), cx);
17353        }
17354
17355        cx.notify();
17356
17357        self.scrollbar_marker_state.dirty = true;
17358        self.folds_did_change(cx);
17359    }
17360
17361    /// Removes any folds whose ranges intersect any of the given ranges.
17362    pub fn unfold_ranges<T: ToOffset + Clone>(
17363        &mut self,
17364        ranges: &[Range<T>],
17365        inclusive: bool,
17366        auto_scroll: bool,
17367        cx: &mut Context<Self>,
17368    ) {
17369        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17370            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17371        });
17372        self.folds_did_change(cx);
17373    }
17374
17375    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17376        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17377            return;
17378        }
17379        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17380        self.display_map.update(cx, |display_map, cx| {
17381            display_map.fold_buffers([buffer_id], cx)
17382        });
17383        cx.emit(EditorEvent::BufferFoldToggled {
17384            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17385            folded: true,
17386        });
17387        cx.notify();
17388    }
17389
17390    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17391        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17392            return;
17393        }
17394        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17395        self.display_map.update(cx, |display_map, cx| {
17396            display_map.unfold_buffers([buffer_id], cx);
17397        });
17398        cx.emit(EditorEvent::BufferFoldToggled {
17399            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17400            folded: false,
17401        });
17402        cx.notify();
17403    }
17404
17405    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17406        self.display_map.read(cx).is_buffer_folded(buffer)
17407    }
17408
17409    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17410        self.display_map.read(cx).folded_buffers()
17411    }
17412
17413    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17414        self.display_map.update(cx, |display_map, cx| {
17415            display_map.disable_header_for_buffer(buffer_id, cx);
17416        });
17417        cx.notify();
17418    }
17419
17420    /// Removes any folds with the given ranges.
17421    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17422        &mut self,
17423        ranges: &[Range<T>],
17424        type_id: TypeId,
17425        auto_scroll: bool,
17426        cx: &mut Context<Self>,
17427    ) {
17428        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17429            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17430        });
17431        self.folds_did_change(cx);
17432    }
17433
17434    fn remove_folds_with<T: ToOffset + Clone>(
17435        &mut self,
17436        ranges: &[Range<T>],
17437        auto_scroll: bool,
17438        cx: &mut Context<Self>,
17439        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17440    ) {
17441        if ranges.is_empty() {
17442            return;
17443        }
17444
17445        let mut buffers_affected = HashSet::default();
17446        let multi_buffer = self.buffer().read(cx);
17447        for range in ranges {
17448            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17449                buffers_affected.insert(buffer.read(cx).remote_id());
17450            };
17451        }
17452
17453        self.display_map.update(cx, update);
17454
17455        if auto_scroll {
17456            self.request_autoscroll(Autoscroll::fit(), cx);
17457        }
17458
17459        cx.notify();
17460        self.scrollbar_marker_state.dirty = true;
17461        self.active_indent_guides_state.dirty = true;
17462    }
17463
17464    pub fn update_renderer_widths(
17465        &mut self,
17466        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17467        cx: &mut Context<Self>,
17468    ) -> bool {
17469        self.display_map
17470            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17471    }
17472
17473    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17474        self.display_map.read(cx).fold_placeholder.clone()
17475    }
17476
17477    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17478        self.buffer.update(cx, |buffer, cx| {
17479            buffer.set_all_diff_hunks_expanded(cx);
17480        });
17481    }
17482
17483    pub fn expand_all_diff_hunks(
17484        &mut self,
17485        _: &ExpandAllDiffHunks,
17486        _window: &mut Window,
17487        cx: &mut Context<Self>,
17488    ) {
17489        self.buffer.update(cx, |buffer, cx| {
17490            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17491        });
17492    }
17493
17494    pub fn toggle_selected_diff_hunks(
17495        &mut self,
17496        _: &ToggleSelectedDiffHunks,
17497        _window: &mut Window,
17498        cx: &mut Context<Self>,
17499    ) {
17500        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17501        self.toggle_diff_hunks_in_ranges(ranges, cx);
17502    }
17503
17504    pub fn diff_hunks_in_ranges<'a>(
17505        &'a self,
17506        ranges: &'a [Range<Anchor>],
17507        buffer: &'a MultiBufferSnapshot,
17508    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17509        ranges.iter().flat_map(move |range| {
17510            let end_excerpt_id = range.end.excerpt_id;
17511            let range = range.to_point(buffer);
17512            let mut peek_end = range.end;
17513            if range.end.row < buffer.max_row().0 {
17514                peek_end = Point::new(range.end.row + 1, 0);
17515            }
17516            buffer
17517                .diff_hunks_in_range(range.start..peek_end)
17518                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17519        })
17520    }
17521
17522    pub fn has_stageable_diff_hunks_in_ranges(
17523        &self,
17524        ranges: &[Range<Anchor>],
17525        snapshot: &MultiBufferSnapshot,
17526    ) -> bool {
17527        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17528        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17529    }
17530
17531    pub fn toggle_staged_selected_diff_hunks(
17532        &mut self,
17533        _: &::git::ToggleStaged,
17534        _: &mut Window,
17535        cx: &mut Context<Self>,
17536    ) {
17537        let snapshot = self.buffer.read(cx).snapshot(cx);
17538        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17539        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17540        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17541    }
17542
17543    pub fn set_render_diff_hunk_controls(
17544        &mut self,
17545        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17546        cx: &mut Context<Self>,
17547    ) {
17548        self.render_diff_hunk_controls = render_diff_hunk_controls;
17549        cx.notify();
17550    }
17551
17552    pub fn stage_and_next(
17553        &mut self,
17554        _: &::git::StageAndNext,
17555        window: &mut Window,
17556        cx: &mut Context<Self>,
17557    ) {
17558        self.do_stage_or_unstage_and_next(true, window, cx);
17559    }
17560
17561    pub fn unstage_and_next(
17562        &mut self,
17563        _: &::git::UnstageAndNext,
17564        window: &mut Window,
17565        cx: &mut Context<Self>,
17566    ) {
17567        self.do_stage_or_unstage_and_next(false, window, cx);
17568    }
17569
17570    pub fn stage_or_unstage_diff_hunks(
17571        &mut self,
17572        stage: bool,
17573        ranges: Vec<Range<Anchor>>,
17574        cx: &mut Context<Self>,
17575    ) {
17576        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17577        cx.spawn(async move |this, cx| {
17578            task.await?;
17579            this.update(cx, |this, cx| {
17580                let snapshot = this.buffer.read(cx).snapshot(cx);
17581                let chunk_by = this
17582                    .diff_hunks_in_ranges(&ranges, &snapshot)
17583                    .chunk_by(|hunk| hunk.buffer_id);
17584                for (buffer_id, hunks) in &chunk_by {
17585                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17586                }
17587            })
17588        })
17589        .detach_and_log_err(cx);
17590    }
17591
17592    fn save_buffers_for_ranges_if_needed(
17593        &mut self,
17594        ranges: &[Range<Anchor>],
17595        cx: &mut Context<Editor>,
17596    ) -> Task<Result<()>> {
17597        let multibuffer = self.buffer.read(cx);
17598        let snapshot = multibuffer.read(cx);
17599        let buffer_ids: HashSet<_> = ranges
17600            .iter()
17601            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17602            .collect();
17603        drop(snapshot);
17604
17605        let mut buffers = HashSet::default();
17606        for buffer_id in buffer_ids {
17607            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17608                let buffer = buffer_entity.read(cx);
17609                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17610                {
17611                    buffers.insert(buffer_entity);
17612                }
17613            }
17614        }
17615
17616        if let Some(project) = &self.project {
17617            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17618        } else {
17619            Task::ready(Ok(()))
17620        }
17621    }
17622
17623    fn do_stage_or_unstage_and_next(
17624        &mut self,
17625        stage: bool,
17626        window: &mut Window,
17627        cx: &mut Context<Self>,
17628    ) {
17629        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17630
17631        if ranges.iter().any(|range| range.start != range.end) {
17632            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17633            return;
17634        }
17635
17636        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17637        let snapshot = self.snapshot(window, cx);
17638        let position = self.selections.newest::<Point>(cx).head();
17639        let mut row = snapshot
17640            .buffer_snapshot
17641            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17642            .find(|hunk| hunk.row_range.start.0 > position.row)
17643            .map(|hunk| hunk.row_range.start);
17644
17645        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17646        // Outside of the project diff editor, wrap around to the beginning.
17647        if !all_diff_hunks_expanded {
17648            row = row.or_else(|| {
17649                snapshot
17650                    .buffer_snapshot
17651                    .diff_hunks_in_range(Point::zero()..position)
17652                    .find(|hunk| hunk.row_range.end.0 < position.row)
17653                    .map(|hunk| hunk.row_range.start)
17654            });
17655        }
17656
17657        if let Some(row) = row {
17658            let destination = Point::new(row.0, 0);
17659            let autoscroll = Autoscroll::center();
17660
17661            self.unfold_ranges(&[destination..destination], false, false, cx);
17662            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17663                s.select_ranges([destination..destination]);
17664            });
17665        }
17666    }
17667
17668    fn do_stage_or_unstage(
17669        &self,
17670        stage: bool,
17671        buffer_id: BufferId,
17672        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17673        cx: &mut App,
17674    ) -> Option<()> {
17675        let project = self.project.as_ref()?;
17676        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17677        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17678        let buffer_snapshot = buffer.read(cx).snapshot();
17679        let file_exists = buffer_snapshot
17680            .file()
17681            .is_some_and(|file| file.disk_state().exists());
17682        diff.update(cx, |diff, cx| {
17683            diff.stage_or_unstage_hunks(
17684                stage,
17685                &hunks
17686                    .map(|hunk| buffer_diff::DiffHunk {
17687                        buffer_range: hunk.buffer_range,
17688                        diff_base_byte_range: hunk.diff_base_byte_range,
17689                        secondary_status: hunk.secondary_status,
17690                        range: Point::zero()..Point::zero(), // unused
17691                    })
17692                    .collect::<Vec<_>>(),
17693                &buffer_snapshot,
17694                file_exists,
17695                cx,
17696            )
17697        });
17698        None
17699    }
17700
17701    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17702        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17703        self.buffer
17704            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17705    }
17706
17707    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17708        self.buffer.update(cx, |buffer, cx| {
17709            let ranges = vec![Anchor::min()..Anchor::max()];
17710            if !buffer.all_diff_hunks_expanded()
17711                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17712            {
17713                buffer.collapse_diff_hunks(ranges, cx);
17714                true
17715            } else {
17716                false
17717            }
17718        })
17719    }
17720
17721    fn toggle_diff_hunks_in_ranges(
17722        &mut self,
17723        ranges: Vec<Range<Anchor>>,
17724        cx: &mut Context<Editor>,
17725    ) {
17726        self.buffer.update(cx, |buffer, cx| {
17727            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17728            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17729        })
17730    }
17731
17732    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17733        self.buffer.update(cx, |buffer, cx| {
17734            let snapshot = buffer.snapshot(cx);
17735            let excerpt_id = range.end.excerpt_id;
17736            let point_range = range.to_point(&snapshot);
17737            let expand = !buffer.single_hunk_is_expanded(range, cx);
17738            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17739        })
17740    }
17741
17742    pub(crate) fn apply_all_diff_hunks(
17743        &mut self,
17744        _: &ApplyAllDiffHunks,
17745        window: &mut Window,
17746        cx: &mut Context<Self>,
17747    ) {
17748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17749
17750        let buffers = self.buffer.read(cx).all_buffers();
17751        for branch_buffer in buffers {
17752            branch_buffer.update(cx, |branch_buffer, cx| {
17753                branch_buffer.merge_into_base(Vec::new(), cx);
17754            });
17755        }
17756
17757        if let Some(project) = self.project.clone() {
17758            self.save(
17759                SaveOptions {
17760                    format: true,
17761                    autosave: false,
17762                },
17763                project,
17764                window,
17765                cx,
17766            )
17767            .detach_and_log_err(cx);
17768        }
17769    }
17770
17771    pub(crate) fn apply_selected_diff_hunks(
17772        &mut self,
17773        _: &ApplyDiffHunk,
17774        window: &mut Window,
17775        cx: &mut Context<Self>,
17776    ) {
17777        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17778        let snapshot = self.snapshot(window, cx);
17779        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17780        let mut ranges_by_buffer = HashMap::default();
17781        self.transact(window, cx, |editor, _window, cx| {
17782            for hunk in hunks {
17783                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17784                    ranges_by_buffer
17785                        .entry(buffer.clone())
17786                        .or_insert_with(Vec::new)
17787                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17788                }
17789            }
17790
17791            for (buffer, ranges) in ranges_by_buffer {
17792                buffer.update(cx, |buffer, cx| {
17793                    buffer.merge_into_base(ranges, cx);
17794                });
17795            }
17796        });
17797
17798        if let Some(project) = self.project.clone() {
17799            self.save(
17800                SaveOptions {
17801                    format: true,
17802                    autosave: false,
17803                },
17804                project,
17805                window,
17806                cx,
17807            )
17808            .detach_and_log_err(cx);
17809        }
17810    }
17811
17812    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17813        if hovered != self.gutter_hovered {
17814            self.gutter_hovered = hovered;
17815            cx.notify();
17816        }
17817    }
17818
17819    pub fn insert_blocks(
17820        &mut self,
17821        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17822        autoscroll: Option<Autoscroll>,
17823        cx: &mut Context<Self>,
17824    ) -> Vec<CustomBlockId> {
17825        let blocks = self
17826            .display_map
17827            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17828        if let Some(autoscroll) = autoscroll {
17829            self.request_autoscroll(autoscroll, cx);
17830        }
17831        cx.notify();
17832        blocks
17833    }
17834
17835    pub fn resize_blocks(
17836        &mut self,
17837        heights: HashMap<CustomBlockId, u32>,
17838        autoscroll: Option<Autoscroll>,
17839        cx: &mut Context<Self>,
17840    ) {
17841        self.display_map
17842            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17843        if let Some(autoscroll) = autoscroll {
17844            self.request_autoscroll(autoscroll, cx);
17845        }
17846        cx.notify();
17847    }
17848
17849    pub fn replace_blocks(
17850        &mut self,
17851        renderers: HashMap<CustomBlockId, RenderBlock>,
17852        autoscroll: Option<Autoscroll>,
17853        cx: &mut Context<Self>,
17854    ) {
17855        self.display_map
17856            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17857        if let Some(autoscroll) = autoscroll {
17858            self.request_autoscroll(autoscroll, cx);
17859        }
17860        cx.notify();
17861    }
17862
17863    pub fn remove_blocks(
17864        &mut self,
17865        block_ids: HashSet<CustomBlockId>,
17866        autoscroll: Option<Autoscroll>,
17867        cx: &mut Context<Self>,
17868    ) {
17869        self.display_map.update(cx, |display_map, cx| {
17870            display_map.remove_blocks(block_ids, cx)
17871        });
17872        if let Some(autoscroll) = autoscroll {
17873            self.request_autoscroll(autoscroll, cx);
17874        }
17875        cx.notify();
17876    }
17877
17878    pub fn row_for_block(
17879        &self,
17880        block_id: CustomBlockId,
17881        cx: &mut Context<Self>,
17882    ) -> Option<DisplayRow> {
17883        self.display_map
17884            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17885    }
17886
17887    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17888        self.focused_block = Some(focused_block);
17889    }
17890
17891    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17892        self.focused_block.take()
17893    }
17894
17895    pub fn insert_creases(
17896        &mut self,
17897        creases: impl IntoIterator<Item = Crease<Anchor>>,
17898        cx: &mut Context<Self>,
17899    ) -> Vec<CreaseId> {
17900        self.display_map
17901            .update(cx, |map, cx| map.insert_creases(creases, cx))
17902    }
17903
17904    pub fn remove_creases(
17905        &mut self,
17906        ids: impl IntoIterator<Item = CreaseId>,
17907        cx: &mut Context<Self>,
17908    ) -> Vec<(CreaseId, Range<Anchor>)> {
17909        self.display_map
17910            .update(cx, |map, cx| map.remove_creases(ids, cx))
17911    }
17912
17913    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17914        self.display_map
17915            .update(cx, |map, cx| map.snapshot(cx))
17916            .longest_row()
17917    }
17918
17919    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17920        self.display_map
17921            .update(cx, |map, cx| map.snapshot(cx))
17922            .max_point()
17923    }
17924
17925    pub fn text(&self, cx: &App) -> String {
17926        self.buffer.read(cx).read(cx).text()
17927    }
17928
17929    pub fn is_empty(&self, cx: &App) -> bool {
17930        self.buffer.read(cx).read(cx).is_empty()
17931    }
17932
17933    pub fn text_option(&self, cx: &App) -> Option<String> {
17934        let text = self.text(cx);
17935        let text = text.trim();
17936
17937        if text.is_empty() {
17938            return None;
17939        }
17940
17941        Some(text.to_string())
17942    }
17943
17944    pub fn set_text(
17945        &mut self,
17946        text: impl Into<Arc<str>>,
17947        window: &mut Window,
17948        cx: &mut Context<Self>,
17949    ) {
17950        self.transact(window, cx, |this, _, cx| {
17951            this.buffer
17952                .read(cx)
17953                .as_singleton()
17954                .expect("you can only call set_text on editors for singleton buffers")
17955                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17956        });
17957    }
17958
17959    pub fn display_text(&self, cx: &mut App) -> String {
17960        self.display_map
17961            .update(cx, |map, cx| map.snapshot(cx))
17962            .text()
17963    }
17964
17965    fn create_minimap(
17966        &self,
17967        minimap_settings: MinimapSettings,
17968        window: &mut Window,
17969        cx: &mut Context<Self>,
17970    ) -> Option<Entity<Self>> {
17971        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17972            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17973    }
17974
17975    fn initialize_new_minimap(
17976        &self,
17977        minimap_settings: MinimapSettings,
17978        window: &mut Window,
17979        cx: &mut Context<Self>,
17980    ) -> Entity<Self> {
17981        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17982
17983        let mut minimap = Editor::new_internal(
17984            EditorMode::Minimap {
17985                parent: cx.weak_entity(),
17986            },
17987            self.buffer.clone(),
17988            self.project.clone(),
17989            Some(self.display_map.clone()),
17990            window,
17991            cx,
17992        );
17993        minimap.scroll_manager.clone_state(&self.scroll_manager);
17994        minimap.set_text_style_refinement(TextStyleRefinement {
17995            font_size: Some(MINIMAP_FONT_SIZE),
17996            font_weight: Some(MINIMAP_FONT_WEIGHT),
17997            ..Default::default()
17998        });
17999        minimap.update_minimap_configuration(minimap_settings, cx);
18000        cx.new(|_| minimap)
18001    }
18002
18003    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18004        let current_line_highlight = minimap_settings
18005            .current_line_highlight
18006            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18007        self.set_current_line_highlight(Some(current_line_highlight));
18008    }
18009
18010    pub fn minimap(&self) -> Option<&Entity<Self>> {
18011        self.minimap
18012            .as_ref()
18013            .filter(|_| self.minimap_visibility.visible())
18014    }
18015
18016    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18017        let mut wrap_guides = smallvec![];
18018
18019        if self.show_wrap_guides == Some(false) {
18020            return wrap_guides;
18021        }
18022
18023        let settings = self.buffer.read(cx).language_settings(cx);
18024        if settings.show_wrap_guides {
18025            match self.soft_wrap_mode(cx) {
18026                SoftWrap::Column(soft_wrap) => {
18027                    wrap_guides.push((soft_wrap as usize, true));
18028                }
18029                SoftWrap::Bounded(soft_wrap) => {
18030                    wrap_guides.push((soft_wrap as usize, true));
18031                }
18032                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18033            }
18034            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18035        }
18036
18037        wrap_guides
18038    }
18039
18040    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18041        let settings = self.buffer.read(cx).language_settings(cx);
18042        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18043        match mode {
18044            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18045                SoftWrap::None
18046            }
18047            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18048            language_settings::SoftWrap::PreferredLineLength => {
18049                SoftWrap::Column(settings.preferred_line_length)
18050            }
18051            language_settings::SoftWrap::Bounded => {
18052                SoftWrap::Bounded(settings.preferred_line_length)
18053            }
18054        }
18055    }
18056
18057    pub fn set_soft_wrap_mode(
18058        &mut self,
18059        mode: language_settings::SoftWrap,
18060
18061        cx: &mut Context<Self>,
18062    ) {
18063        self.soft_wrap_mode_override = Some(mode);
18064        cx.notify();
18065    }
18066
18067    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18068        self.hard_wrap = hard_wrap;
18069        cx.notify();
18070    }
18071
18072    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18073        self.text_style_refinement = Some(style);
18074    }
18075
18076    /// called by the Element so we know what style we were most recently rendered with.
18077    pub(crate) fn set_style(
18078        &mut self,
18079        style: EditorStyle,
18080        window: &mut Window,
18081        cx: &mut Context<Self>,
18082    ) {
18083        // We intentionally do not inform the display map about the minimap style
18084        // so that wrapping is not recalculated and stays consistent for the editor
18085        // and its linked minimap.
18086        if !self.mode.is_minimap() {
18087            let rem_size = window.rem_size();
18088            self.display_map.update(cx, |map, cx| {
18089                map.set_font(
18090                    style.text.font(),
18091                    style.text.font_size.to_pixels(rem_size),
18092                    cx,
18093                )
18094            });
18095        }
18096        self.style = Some(style);
18097    }
18098
18099    pub fn style(&self) -> Option<&EditorStyle> {
18100        self.style.as_ref()
18101    }
18102
18103    // Called by the element. This method is not designed to be called outside of the editor
18104    // element's layout code because it does not notify when rewrapping is computed synchronously.
18105    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18106        self.display_map
18107            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18108    }
18109
18110    pub fn set_soft_wrap(&mut self) {
18111        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18112    }
18113
18114    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18115        if self.soft_wrap_mode_override.is_some() {
18116            self.soft_wrap_mode_override.take();
18117        } else {
18118            let soft_wrap = match self.soft_wrap_mode(cx) {
18119                SoftWrap::GitDiff => return,
18120                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18121                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18122                    language_settings::SoftWrap::None
18123                }
18124            };
18125            self.soft_wrap_mode_override = Some(soft_wrap);
18126        }
18127        cx.notify();
18128    }
18129
18130    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18131        let Some(workspace) = self.workspace() else {
18132            return;
18133        };
18134        let fs = workspace.read(cx).app_state().fs.clone();
18135        let current_show = TabBarSettings::get_global(cx).show;
18136        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18137            setting.show = Some(!current_show);
18138        });
18139    }
18140
18141    pub fn toggle_indent_guides(
18142        &mut self,
18143        _: &ToggleIndentGuides,
18144        _: &mut Window,
18145        cx: &mut Context<Self>,
18146    ) {
18147        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18148            self.buffer
18149                .read(cx)
18150                .language_settings(cx)
18151                .indent_guides
18152                .enabled
18153        });
18154        self.show_indent_guides = Some(!currently_enabled);
18155        cx.notify();
18156    }
18157
18158    fn should_show_indent_guides(&self) -> Option<bool> {
18159        self.show_indent_guides
18160    }
18161
18162    pub fn toggle_line_numbers(
18163        &mut self,
18164        _: &ToggleLineNumbers,
18165        _: &mut Window,
18166        cx: &mut Context<Self>,
18167    ) {
18168        let mut editor_settings = EditorSettings::get_global(cx).clone();
18169        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18170        EditorSettings::override_global(editor_settings, cx);
18171    }
18172
18173    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18174        if let Some(show_line_numbers) = self.show_line_numbers {
18175            return show_line_numbers;
18176        }
18177        EditorSettings::get_global(cx).gutter.line_numbers
18178    }
18179
18180    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18181        self.use_relative_line_numbers
18182            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18183    }
18184
18185    pub fn toggle_relative_line_numbers(
18186        &mut self,
18187        _: &ToggleRelativeLineNumbers,
18188        _: &mut Window,
18189        cx: &mut Context<Self>,
18190    ) {
18191        let is_relative = self.should_use_relative_line_numbers(cx);
18192        self.set_relative_line_number(Some(!is_relative), cx)
18193    }
18194
18195    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18196        self.use_relative_line_numbers = is_relative;
18197        cx.notify();
18198    }
18199
18200    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18201        self.show_gutter = show_gutter;
18202        cx.notify();
18203    }
18204
18205    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18206        self.show_scrollbars = ScrollbarAxes {
18207            horizontal: show,
18208            vertical: show,
18209        };
18210        cx.notify();
18211    }
18212
18213    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18214        self.show_scrollbars.vertical = show;
18215        cx.notify();
18216    }
18217
18218    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18219        self.show_scrollbars.horizontal = show;
18220        cx.notify();
18221    }
18222
18223    pub fn set_minimap_visibility(
18224        &mut self,
18225        minimap_visibility: MinimapVisibility,
18226        window: &mut Window,
18227        cx: &mut Context<Self>,
18228    ) {
18229        if self.minimap_visibility != minimap_visibility {
18230            if minimap_visibility.visible() && self.minimap.is_none() {
18231                let minimap_settings = EditorSettings::get_global(cx).minimap;
18232                self.minimap =
18233                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18234            }
18235            self.minimap_visibility = minimap_visibility;
18236            cx.notify();
18237        }
18238    }
18239
18240    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18241        self.set_show_scrollbars(false, cx);
18242        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18243    }
18244
18245    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18246        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18247    }
18248
18249    /// Normally the text in full mode and auto height editors is padded on the
18250    /// left side by roughly half a character width for improved hit testing.
18251    ///
18252    /// Use this method to disable this for cases where this is not wanted (e.g.
18253    /// if you want to align the editor text with some other text above or below)
18254    /// or if you want to add this padding to single-line editors.
18255    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18256        self.offset_content = offset_content;
18257        cx.notify();
18258    }
18259
18260    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18261        self.show_line_numbers = Some(show_line_numbers);
18262        cx.notify();
18263    }
18264
18265    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18266        self.disable_expand_excerpt_buttons = true;
18267        cx.notify();
18268    }
18269
18270    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18271        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18272        cx.notify();
18273    }
18274
18275    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18276        self.show_code_actions = Some(show_code_actions);
18277        cx.notify();
18278    }
18279
18280    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18281        self.show_runnables = Some(show_runnables);
18282        cx.notify();
18283    }
18284
18285    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18286        self.show_breakpoints = Some(show_breakpoints);
18287        cx.notify();
18288    }
18289
18290    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18291        if self.display_map.read(cx).masked != masked {
18292            self.display_map.update(cx, |map, _| map.masked = masked);
18293        }
18294        cx.notify()
18295    }
18296
18297    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18298        self.show_wrap_guides = Some(show_wrap_guides);
18299        cx.notify();
18300    }
18301
18302    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18303        self.show_indent_guides = Some(show_indent_guides);
18304        cx.notify();
18305    }
18306
18307    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18308        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18309            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18310                if let Some(dir) = file.abs_path(cx).parent() {
18311                    return Some(dir.to_owned());
18312                }
18313            }
18314
18315            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18316                return Some(project_path.path.to_path_buf());
18317            }
18318        }
18319
18320        None
18321    }
18322
18323    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18324        self.active_excerpt(cx)?
18325            .1
18326            .read(cx)
18327            .file()
18328            .and_then(|f| f.as_local())
18329    }
18330
18331    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18332        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18333            let buffer = buffer.read(cx);
18334            if let Some(project_path) = buffer.project_path(cx) {
18335                let project = self.project.as_ref()?.read(cx);
18336                project.absolute_path(&project_path, cx)
18337            } else {
18338                buffer
18339                    .file()
18340                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18341            }
18342        })
18343    }
18344
18345    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18346        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18347            let project_path = buffer.read(cx).project_path(cx)?;
18348            let project = self.project.as_ref()?.read(cx);
18349            let entry = project.entry_for_path(&project_path, cx)?;
18350            let path = entry.path.to_path_buf();
18351            Some(path)
18352        })
18353    }
18354
18355    pub fn reveal_in_finder(
18356        &mut self,
18357        _: &RevealInFileManager,
18358        _window: &mut Window,
18359        cx: &mut Context<Self>,
18360    ) {
18361        if let Some(target) = self.target_file(cx) {
18362            cx.reveal_path(&target.abs_path(cx));
18363        }
18364    }
18365
18366    pub fn copy_path(
18367        &mut self,
18368        _: &zed_actions::workspace::CopyPath,
18369        _window: &mut Window,
18370        cx: &mut Context<Self>,
18371    ) {
18372        if let Some(path) = self.target_file_abs_path(cx) {
18373            if let Some(path) = path.to_str() {
18374                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18375            }
18376        }
18377    }
18378
18379    pub fn copy_relative_path(
18380        &mut self,
18381        _: &zed_actions::workspace::CopyRelativePath,
18382        _window: &mut Window,
18383        cx: &mut Context<Self>,
18384    ) {
18385        if let Some(path) = self.target_file_path(cx) {
18386            if let Some(path) = path.to_str() {
18387                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18388            }
18389        }
18390    }
18391
18392    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18393        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18394            buffer.read(cx).project_path(cx)
18395        } else {
18396            None
18397        }
18398    }
18399
18400    // Returns true if the editor handled a go-to-line request
18401    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18402        maybe!({
18403            let breakpoint_store = self.breakpoint_store.as_ref()?;
18404
18405            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18406            else {
18407                self.clear_row_highlights::<ActiveDebugLine>();
18408                return None;
18409            };
18410
18411            let position = active_stack_frame.position;
18412            let buffer_id = position.buffer_id?;
18413            let snapshot = self
18414                .project
18415                .as_ref()?
18416                .read(cx)
18417                .buffer_for_id(buffer_id, cx)?
18418                .read(cx)
18419                .snapshot();
18420
18421            let mut handled = false;
18422            for (id, ExcerptRange { context, .. }) in
18423                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18424            {
18425                if context.start.cmp(&position, &snapshot).is_ge()
18426                    || context.end.cmp(&position, &snapshot).is_lt()
18427                {
18428                    continue;
18429                }
18430                let snapshot = self.buffer.read(cx).snapshot(cx);
18431                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18432
18433                handled = true;
18434                self.clear_row_highlights::<ActiveDebugLine>();
18435
18436                self.go_to_line::<ActiveDebugLine>(
18437                    multibuffer_anchor,
18438                    Some(cx.theme().colors().editor_debugger_active_line_background),
18439                    window,
18440                    cx,
18441                );
18442
18443                cx.notify();
18444            }
18445
18446            handled.then_some(())
18447        })
18448        .is_some()
18449    }
18450
18451    pub fn copy_file_name_without_extension(
18452        &mut self,
18453        _: &CopyFileNameWithoutExtension,
18454        _: &mut Window,
18455        cx: &mut Context<Self>,
18456    ) {
18457        if let Some(file) = self.target_file(cx) {
18458            if let Some(file_stem) = file.path().file_stem() {
18459                if let Some(name) = file_stem.to_str() {
18460                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18461                }
18462            }
18463        }
18464    }
18465
18466    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18467        if let Some(file) = self.target_file(cx) {
18468            if let Some(file_name) = file.path().file_name() {
18469                if let Some(name) = file_name.to_str() {
18470                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18471                }
18472            }
18473        }
18474    }
18475
18476    pub fn toggle_git_blame(
18477        &mut self,
18478        _: &::git::Blame,
18479        window: &mut Window,
18480        cx: &mut Context<Self>,
18481    ) {
18482        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18483
18484        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18485            self.start_git_blame(true, window, cx);
18486        }
18487
18488        cx.notify();
18489    }
18490
18491    pub fn toggle_git_blame_inline(
18492        &mut self,
18493        _: &ToggleGitBlameInline,
18494        window: &mut Window,
18495        cx: &mut Context<Self>,
18496    ) {
18497        self.toggle_git_blame_inline_internal(true, window, cx);
18498        cx.notify();
18499    }
18500
18501    pub fn open_git_blame_commit(
18502        &mut self,
18503        _: &OpenGitBlameCommit,
18504        window: &mut Window,
18505        cx: &mut Context<Self>,
18506    ) {
18507        self.open_git_blame_commit_internal(window, cx);
18508    }
18509
18510    fn open_git_blame_commit_internal(
18511        &mut self,
18512        window: &mut Window,
18513        cx: &mut Context<Self>,
18514    ) -> Option<()> {
18515        let blame = self.blame.as_ref()?;
18516        let snapshot = self.snapshot(window, cx);
18517        let cursor = self.selections.newest::<Point>(cx).head();
18518        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18519        let blame_entry = blame
18520            .update(cx, |blame, cx| {
18521                blame
18522                    .blame_for_rows(
18523                        &[RowInfo {
18524                            buffer_id: Some(buffer.remote_id()),
18525                            buffer_row: Some(point.row),
18526                            ..Default::default()
18527                        }],
18528                        cx,
18529                    )
18530                    .next()
18531            })
18532            .flatten()?;
18533        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18534        let repo = blame.read(cx).repository(cx)?;
18535        let workspace = self.workspace()?.downgrade();
18536        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18537        None
18538    }
18539
18540    pub fn git_blame_inline_enabled(&self) -> bool {
18541        self.git_blame_inline_enabled
18542    }
18543
18544    pub fn toggle_selection_menu(
18545        &mut self,
18546        _: &ToggleSelectionMenu,
18547        _: &mut Window,
18548        cx: &mut Context<Self>,
18549    ) {
18550        self.show_selection_menu = self
18551            .show_selection_menu
18552            .map(|show_selections_menu| !show_selections_menu)
18553            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18554
18555        cx.notify();
18556    }
18557
18558    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18559        self.show_selection_menu
18560            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18561    }
18562
18563    fn start_git_blame(
18564        &mut self,
18565        user_triggered: bool,
18566        window: &mut Window,
18567        cx: &mut Context<Self>,
18568    ) {
18569        if let Some(project) = self.project.as_ref() {
18570            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18571                return;
18572            };
18573
18574            if buffer.read(cx).file().is_none() {
18575                return;
18576            }
18577
18578            let focused = self.focus_handle(cx).contains_focused(window, cx);
18579
18580            let project = project.clone();
18581            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18582            self.blame_subscription =
18583                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18584            self.blame = Some(blame);
18585        }
18586    }
18587
18588    fn toggle_git_blame_inline_internal(
18589        &mut self,
18590        user_triggered: bool,
18591        window: &mut Window,
18592        cx: &mut Context<Self>,
18593    ) {
18594        if self.git_blame_inline_enabled {
18595            self.git_blame_inline_enabled = false;
18596            self.show_git_blame_inline = false;
18597            self.show_git_blame_inline_delay_task.take();
18598        } else {
18599            self.git_blame_inline_enabled = true;
18600            self.start_git_blame_inline(user_triggered, window, cx);
18601        }
18602
18603        cx.notify();
18604    }
18605
18606    fn start_git_blame_inline(
18607        &mut self,
18608        user_triggered: bool,
18609        window: &mut Window,
18610        cx: &mut Context<Self>,
18611    ) {
18612        self.start_git_blame(user_triggered, window, cx);
18613
18614        if ProjectSettings::get_global(cx)
18615            .git
18616            .inline_blame_delay()
18617            .is_some()
18618        {
18619            self.start_inline_blame_timer(window, cx);
18620        } else {
18621            self.show_git_blame_inline = true
18622        }
18623    }
18624
18625    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18626        self.blame.as_ref()
18627    }
18628
18629    pub fn show_git_blame_gutter(&self) -> bool {
18630        self.show_git_blame_gutter
18631    }
18632
18633    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18634        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18635    }
18636
18637    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18638        self.show_git_blame_inline
18639            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18640            && !self.newest_selection_head_on_empty_line(cx)
18641            && self.has_blame_entries(cx)
18642    }
18643
18644    fn has_blame_entries(&self, cx: &App) -> bool {
18645        self.blame()
18646            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18647    }
18648
18649    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18650        let cursor_anchor = self.selections.newest_anchor().head();
18651
18652        let snapshot = self.buffer.read(cx).snapshot(cx);
18653        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18654
18655        snapshot.line_len(buffer_row) == 0
18656    }
18657
18658    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18659        let buffer_and_selection = maybe!({
18660            let selection = self.selections.newest::<Point>(cx);
18661            let selection_range = selection.range();
18662
18663            let multi_buffer = self.buffer().read(cx);
18664            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18665            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18666
18667            let (buffer, range, _) = if selection.reversed {
18668                buffer_ranges.first()
18669            } else {
18670                buffer_ranges.last()
18671            }?;
18672
18673            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18674                ..text::ToPoint::to_point(&range.end, &buffer).row;
18675            Some((
18676                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18677                selection,
18678            ))
18679        });
18680
18681        let Some((buffer, selection)) = buffer_and_selection else {
18682            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18683        };
18684
18685        let Some(project) = self.project.as_ref() else {
18686            return Task::ready(Err(anyhow!("editor does not have project")));
18687        };
18688
18689        project.update(cx, |project, cx| {
18690            project.get_permalink_to_line(&buffer, selection, cx)
18691        })
18692    }
18693
18694    pub fn copy_permalink_to_line(
18695        &mut self,
18696        _: &CopyPermalinkToLine,
18697        window: &mut Window,
18698        cx: &mut Context<Self>,
18699    ) {
18700        let permalink_task = self.get_permalink_to_line(cx);
18701        let workspace = self.workspace();
18702
18703        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18704            Ok(permalink) => {
18705                cx.update(|_, cx| {
18706                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18707                })
18708                .ok();
18709            }
18710            Err(err) => {
18711                let message = format!("Failed to copy permalink: {err}");
18712
18713                anyhow::Result::<()>::Err(err).log_err();
18714
18715                if let Some(workspace) = workspace {
18716                    workspace
18717                        .update_in(cx, |workspace, _, cx| {
18718                            struct CopyPermalinkToLine;
18719
18720                            workspace.show_toast(
18721                                Toast::new(
18722                                    NotificationId::unique::<CopyPermalinkToLine>(),
18723                                    message,
18724                                ),
18725                                cx,
18726                            )
18727                        })
18728                        .ok();
18729                }
18730            }
18731        })
18732        .detach();
18733    }
18734
18735    pub fn copy_file_location(
18736        &mut self,
18737        _: &CopyFileLocation,
18738        _: &mut Window,
18739        cx: &mut Context<Self>,
18740    ) {
18741        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18742        if let Some(file) = self.target_file(cx) {
18743            if let Some(path) = file.path().to_str() {
18744                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18745            }
18746        }
18747    }
18748
18749    pub fn open_permalink_to_line(
18750        &mut self,
18751        _: &OpenPermalinkToLine,
18752        window: &mut Window,
18753        cx: &mut Context<Self>,
18754    ) {
18755        let permalink_task = self.get_permalink_to_line(cx);
18756        let workspace = self.workspace();
18757
18758        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18759            Ok(permalink) => {
18760                cx.update(|_, cx| {
18761                    cx.open_url(permalink.as_ref());
18762                })
18763                .ok();
18764            }
18765            Err(err) => {
18766                let message = format!("Failed to open permalink: {err}");
18767
18768                anyhow::Result::<()>::Err(err).log_err();
18769
18770                if let Some(workspace) = workspace {
18771                    workspace
18772                        .update(cx, |workspace, cx| {
18773                            struct OpenPermalinkToLine;
18774
18775                            workspace.show_toast(
18776                                Toast::new(
18777                                    NotificationId::unique::<OpenPermalinkToLine>(),
18778                                    message,
18779                                ),
18780                                cx,
18781                            )
18782                        })
18783                        .ok();
18784                }
18785            }
18786        })
18787        .detach();
18788    }
18789
18790    pub fn insert_uuid_v4(
18791        &mut self,
18792        _: &InsertUuidV4,
18793        window: &mut Window,
18794        cx: &mut Context<Self>,
18795    ) {
18796        self.insert_uuid(UuidVersion::V4, window, cx);
18797    }
18798
18799    pub fn insert_uuid_v7(
18800        &mut self,
18801        _: &InsertUuidV7,
18802        window: &mut Window,
18803        cx: &mut Context<Self>,
18804    ) {
18805        self.insert_uuid(UuidVersion::V7, window, cx);
18806    }
18807
18808    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18809        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18810        self.transact(window, cx, |this, window, cx| {
18811            let edits = this
18812                .selections
18813                .all::<Point>(cx)
18814                .into_iter()
18815                .map(|selection| {
18816                    let uuid = match version {
18817                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18818                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18819                    };
18820
18821                    (selection.range(), uuid.to_string())
18822                });
18823            this.edit(edits, cx);
18824            this.refresh_inline_completion(true, false, window, cx);
18825        });
18826    }
18827
18828    pub fn open_selections_in_multibuffer(
18829        &mut self,
18830        _: &OpenSelectionsInMultibuffer,
18831        window: &mut Window,
18832        cx: &mut Context<Self>,
18833    ) {
18834        let multibuffer = self.buffer.read(cx);
18835
18836        let Some(buffer) = multibuffer.as_singleton() else {
18837            return;
18838        };
18839
18840        let Some(workspace) = self.workspace() else {
18841            return;
18842        };
18843
18844        let title = multibuffer.title(cx).to_string();
18845
18846        let locations = self
18847            .selections
18848            .all_anchors(cx)
18849            .into_iter()
18850            .map(|selection| Location {
18851                buffer: buffer.clone(),
18852                range: selection.start.text_anchor..selection.end.text_anchor,
18853            })
18854            .collect::<Vec<_>>();
18855
18856        cx.spawn_in(window, async move |_, cx| {
18857            workspace.update_in(cx, |workspace, window, cx| {
18858                Self::open_locations_in_multibuffer(
18859                    workspace,
18860                    locations,
18861                    format!("Selections for '{title}'"),
18862                    false,
18863                    MultibufferSelectionMode::All,
18864                    window,
18865                    cx,
18866                );
18867            })
18868        })
18869        .detach();
18870    }
18871
18872    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18873    /// last highlight added will be used.
18874    ///
18875    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18876    pub fn highlight_rows<T: 'static>(
18877        &mut self,
18878        range: Range<Anchor>,
18879        color: Hsla,
18880        options: RowHighlightOptions,
18881        cx: &mut Context<Self>,
18882    ) {
18883        let snapshot = self.buffer().read(cx).snapshot(cx);
18884        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18885        let ix = row_highlights.binary_search_by(|highlight| {
18886            Ordering::Equal
18887                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18888                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18889        });
18890
18891        if let Err(mut ix) = ix {
18892            let index = post_inc(&mut self.highlight_order);
18893
18894            // If this range intersects with the preceding highlight, then merge it with
18895            // the preceding highlight. Otherwise insert a new highlight.
18896            let mut merged = false;
18897            if ix > 0 {
18898                let prev_highlight = &mut row_highlights[ix - 1];
18899                if prev_highlight
18900                    .range
18901                    .end
18902                    .cmp(&range.start, &snapshot)
18903                    .is_ge()
18904                {
18905                    ix -= 1;
18906                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18907                        prev_highlight.range.end = range.end;
18908                    }
18909                    merged = true;
18910                    prev_highlight.index = index;
18911                    prev_highlight.color = color;
18912                    prev_highlight.options = options;
18913                }
18914            }
18915
18916            if !merged {
18917                row_highlights.insert(
18918                    ix,
18919                    RowHighlight {
18920                        range: range.clone(),
18921                        index,
18922                        color,
18923                        options,
18924                        type_id: TypeId::of::<T>(),
18925                    },
18926                );
18927            }
18928
18929            // If any of the following highlights intersect with this one, merge them.
18930            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18931                let highlight = &row_highlights[ix];
18932                if next_highlight
18933                    .range
18934                    .start
18935                    .cmp(&highlight.range.end, &snapshot)
18936                    .is_le()
18937                {
18938                    if next_highlight
18939                        .range
18940                        .end
18941                        .cmp(&highlight.range.end, &snapshot)
18942                        .is_gt()
18943                    {
18944                        row_highlights[ix].range.end = next_highlight.range.end;
18945                    }
18946                    row_highlights.remove(ix + 1);
18947                } else {
18948                    break;
18949                }
18950            }
18951        }
18952    }
18953
18954    /// Remove any highlighted row ranges of the given type that intersect the
18955    /// given ranges.
18956    pub fn remove_highlighted_rows<T: 'static>(
18957        &mut self,
18958        ranges_to_remove: Vec<Range<Anchor>>,
18959        cx: &mut Context<Self>,
18960    ) {
18961        let snapshot = self.buffer().read(cx).snapshot(cx);
18962        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18963        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18964        row_highlights.retain(|highlight| {
18965            while let Some(range_to_remove) = ranges_to_remove.peek() {
18966                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18967                    Ordering::Less | Ordering::Equal => {
18968                        ranges_to_remove.next();
18969                    }
18970                    Ordering::Greater => {
18971                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18972                            Ordering::Less | Ordering::Equal => {
18973                                return false;
18974                            }
18975                            Ordering::Greater => break,
18976                        }
18977                    }
18978                }
18979            }
18980
18981            true
18982        })
18983    }
18984
18985    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18986    pub fn clear_row_highlights<T: 'static>(&mut self) {
18987        self.highlighted_rows.remove(&TypeId::of::<T>());
18988    }
18989
18990    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18991    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18992        self.highlighted_rows
18993            .get(&TypeId::of::<T>())
18994            .map_or(&[] as &[_], |vec| vec.as_slice())
18995            .iter()
18996            .map(|highlight| (highlight.range.clone(), highlight.color))
18997    }
18998
18999    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19000    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19001    /// Allows to ignore certain kinds of highlights.
19002    pub fn highlighted_display_rows(
19003        &self,
19004        window: &mut Window,
19005        cx: &mut App,
19006    ) -> BTreeMap<DisplayRow, LineHighlight> {
19007        let snapshot = self.snapshot(window, cx);
19008        let mut used_highlight_orders = HashMap::default();
19009        self.highlighted_rows
19010            .iter()
19011            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19012            .fold(
19013                BTreeMap::<DisplayRow, LineHighlight>::new(),
19014                |mut unique_rows, highlight| {
19015                    let start = highlight.range.start.to_display_point(&snapshot);
19016                    let end = highlight.range.end.to_display_point(&snapshot);
19017                    let start_row = start.row().0;
19018                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19019                        && end.column() == 0
19020                    {
19021                        end.row().0.saturating_sub(1)
19022                    } else {
19023                        end.row().0
19024                    };
19025                    for row in start_row..=end_row {
19026                        let used_index =
19027                            used_highlight_orders.entry(row).or_insert(highlight.index);
19028                        if highlight.index >= *used_index {
19029                            *used_index = highlight.index;
19030                            unique_rows.insert(
19031                                DisplayRow(row),
19032                                LineHighlight {
19033                                    include_gutter: highlight.options.include_gutter,
19034                                    border: None,
19035                                    background: highlight.color.into(),
19036                                    type_id: Some(highlight.type_id),
19037                                },
19038                            );
19039                        }
19040                    }
19041                    unique_rows
19042                },
19043            )
19044    }
19045
19046    pub fn highlighted_display_row_for_autoscroll(
19047        &self,
19048        snapshot: &DisplaySnapshot,
19049    ) -> Option<DisplayRow> {
19050        self.highlighted_rows
19051            .values()
19052            .flat_map(|highlighted_rows| highlighted_rows.iter())
19053            .filter_map(|highlight| {
19054                if highlight.options.autoscroll {
19055                    Some(highlight.range.start.to_display_point(snapshot).row())
19056                } else {
19057                    None
19058                }
19059            })
19060            .min()
19061    }
19062
19063    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19064        self.highlight_background::<SearchWithinRange>(
19065            ranges,
19066            |colors| colors.colors().editor_document_highlight_read_background,
19067            cx,
19068        )
19069    }
19070
19071    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19072        self.breadcrumb_header = Some(new_header);
19073    }
19074
19075    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19076        self.clear_background_highlights::<SearchWithinRange>(cx);
19077    }
19078
19079    pub fn highlight_background<T: 'static>(
19080        &mut self,
19081        ranges: &[Range<Anchor>],
19082        color_fetcher: fn(&Theme) -> Hsla,
19083        cx: &mut Context<Self>,
19084    ) {
19085        self.background_highlights.insert(
19086            HighlightKey::Type(TypeId::of::<T>()),
19087            (color_fetcher, Arc::from(ranges)),
19088        );
19089        self.scrollbar_marker_state.dirty = true;
19090        cx.notify();
19091    }
19092
19093    pub fn highlight_background_key<T: 'static>(
19094        &mut self,
19095        key: usize,
19096        ranges: &[Range<Anchor>],
19097        color_fetcher: fn(&Theme) -> Hsla,
19098        cx: &mut Context<Self>,
19099    ) {
19100        self.background_highlights.insert(
19101            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19102            (color_fetcher, Arc::from(ranges)),
19103        );
19104        self.scrollbar_marker_state.dirty = true;
19105        cx.notify();
19106    }
19107
19108    pub fn clear_background_highlights<T: 'static>(
19109        &mut self,
19110        cx: &mut Context<Self>,
19111    ) -> Option<BackgroundHighlight> {
19112        let text_highlights = self
19113            .background_highlights
19114            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19115        if !text_highlights.1.is_empty() {
19116            self.scrollbar_marker_state.dirty = true;
19117            cx.notify();
19118        }
19119        Some(text_highlights)
19120    }
19121
19122    pub fn highlight_gutter<T: 'static>(
19123        &mut self,
19124        ranges: impl Into<Vec<Range<Anchor>>>,
19125        color_fetcher: fn(&App) -> Hsla,
19126        cx: &mut Context<Self>,
19127    ) {
19128        self.gutter_highlights
19129            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19130        cx.notify();
19131    }
19132
19133    pub fn clear_gutter_highlights<T: 'static>(
19134        &mut self,
19135        cx: &mut Context<Self>,
19136    ) -> Option<GutterHighlight> {
19137        cx.notify();
19138        self.gutter_highlights.remove(&TypeId::of::<T>())
19139    }
19140
19141    pub fn insert_gutter_highlight<T: 'static>(
19142        &mut self,
19143        range: Range<Anchor>,
19144        color_fetcher: fn(&App) -> Hsla,
19145        cx: &mut Context<Self>,
19146    ) {
19147        let snapshot = self.buffer().read(cx).snapshot(cx);
19148        let mut highlights = self
19149            .gutter_highlights
19150            .remove(&TypeId::of::<T>())
19151            .map(|(_, highlights)| highlights)
19152            .unwrap_or_default();
19153        let ix = highlights.binary_search_by(|highlight| {
19154            Ordering::Equal
19155                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19156                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19157        });
19158        if let Err(ix) = ix {
19159            highlights.insert(ix, range);
19160        }
19161        self.gutter_highlights
19162            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19163    }
19164
19165    pub fn remove_gutter_highlights<T: 'static>(
19166        &mut self,
19167        ranges_to_remove: Vec<Range<Anchor>>,
19168        cx: &mut Context<Self>,
19169    ) {
19170        let snapshot = self.buffer().read(cx).snapshot(cx);
19171        let Some((color_fetcher, mut gutter_highlights)) =
19172            self.gutter_highlights.remove(&TypeId::of::<T>())
19173        else {
19174            return;
19175        };
19176        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19177        gutter_highlights.retain(|highlight| {
19178            while let Some(range_to_remove) = ranges_to_remove.peek() {
19179                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19180                    Ordering::Less | Ordering::Equal => {
19181                        ranges_to_remove.next();
19182                    }
19183                    Ordering::Greater => {
19184                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19185                            Ordering::Less | Ordering::Equal => {
19186                                return false;
19187                            }
19188                            Ordering::Greater => break,
19189                        }
19190                    }
19191                }
19192            }
19193
19194            true
19195        });
19196        self.gutter_highlights
19197            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19198    }
19199
19200    #[cfg(feature = "test-support")]
19201    pub fn all_text_highlights(
19202        &self,
19203        window: &mut Window,
19204        cx: &mut Context<Self>,
19205    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19206        let snapshot = self.snapshot(window, cx);
19207        self.display_map.update(cx, |display_map, _| {
19208            display_map
19209                .all_text_highlights()
19210                .map(|highlight| {
19211                    let (style, ranges) = highlight.as_ref();
19212                    (
19213                        *style,
19214                        ranges
19215                            .iter()
19216                            .map(|range| range.clone().to_display_points(&snapshot))
19217                            .collect(),
19218                    )
19219                })
19220                .collect()
19221        })
19222    }
19223
19224    #[cfg(feature = "test-support")]
19225    pub fn all_text_background_highlights(
19226        &self,
19227        window: &mut Window,
19228        cx: &mut Context<Self>,
19229    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19230        let snapshot = self.snapshot(window, cx);
19231        let buffer = &snapshot.buffer_snapshot;
19232        let start = buffer.anchor_before(0);
19233        let end = buffer.anchor_after(buffer.len());
19234        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19235    }
19236
19237    #[cfg(feature = "test-support")]
19238    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19239        let snapshot = self.buffer().read(cx).snapshot(cx);
19240
19241        let highlights = self
19242            .background_highlights
19243            .get(&HighlightKey::Type(TypeId::of::<
19244                items::BufferSearchHighlights,
19245            >()));
19246
19247        if let Some((_color, ranges)) = highlights {
19248            ranges
19249                .iter()
19250                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19251                .collect_vec()
19252        } else {
19253            vec![]
19254        }
19255    }
19256
19257    fn document_highlights_for_position<'a>(
19258        &'a self,
19259        position: Anchor,
19260        buffer: &'a MultiBufferSnapshot,
19261    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19262        let read_highlights = self
19263            .background_highlights
19264            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19265            .map(|h| &h.1);
19266        let write_highlights = self
19267            .background_highlights
19268            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19269            .map(|h| &h.1);
19270        let left_position = position.bias_left(buffer);
19271        let right_position = position.bias_right(buffer);
19272        read_highlights
19273            .into_iter()
19274            .chain(write_highlights)
19275            .flat_map(move |ranges| {
19276                let start_ix = match ranges.binary_search_by(|probe| {
19277                    let cmp = probe.end.cmp(&left_position, buffer);
19278                    if cmp.is_ge() {
19279                        Ordering::Greater
19280                    } else {
19281                        Ordering::Less
19282                    }
19283                }) {
19284                    Ok(i) | Err(i) => i,
19285                };
19286
19287                ranges[start_ix..]
19288                    .iter()
19289                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19290            })
19291    }
19292
19293    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19294        self.background_highlights
19295            .get(&HighlightKey::Type(TypeId::of::<T>()))
19296            .map_or(false, |(_, highlights)| !highlights.is_empty())
19297    }
19298
19299    pub fn background_highlights_in_range(
19300        &self,
19301        search_range: Range<Anchor>,
19302        display_snapshot: &DisplaySnapshot,
19303        theme: &Theme,
19304    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19305        let mut results = Vec::new();
19306        for (color_fetcher, ranges) in self.background_highlights.values() {
19307            let color = color_fetcher(theme);
19308            let start_ix = match ranges.binary_search_by(|probe| {
19309                let cmp = probe
19310                    .end
19311                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19312                if cmp.is_gt() {
19313                    Ordering::Greater
19314                } else {
19315                    Ordering::Less
19316                }
19317            }) {
19318                Ok(i) | Err(i) => i,
19319            };
19320            for range in &ranges[start_ix..] {
19321                if range
19322                    .start
19323                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19324                    .is_ge()
19325                {
19326                    break;
19327                }
19328
19329                let start = range.start.to_display_point(display_snapshot);
19330                let end = range.end.to_display_point(display_snapshot);
19331                results.push((start..end, color))
19332            }
19333        }
19334        results
19335    }
19336
19337    pub fn background_highlight_row_ranges<T: 'static>(
19338        &self,
19339        search_range: Range<Anchor>,
19340        display_snapshot: &DisplaySnapshot,
19341        count: usize,
19342    ) -> Vec<RangeInclusive<DisplayPoint>> {
19343        let mut results = Vec::new();
19344        let Some((_, ranges)) = self
19345            .background_highlights
19346            .get(&HighlightKey::Type(TypeId::of::<T>()))
19347        else {
19348            return vec![];
19349        };
19350
19351        let start_ix = match ranges.binary_search_by(|probe| {
19352            let cmp = probe
19353                .end
19354                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19355            if cmp.is_gt() {
19356                Ordering::Greater
19357            } else {
19358                Ordering::Less
19359            }
19360        }) {
19361            Ok(i) | Err(i) => i,
19362        };
19363        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19364            if let (Some(start_display), Some(end_display)) = (start, end) {
19365                results.push(
19366                    start_display.to_display_point(display_snapshot)
19367                        ..=end_display.to_display_point(display_snapshot),
19368                );
19369            }
19370        };
19371        let mut start_row: Option<Point> = None;
19372        let mut end_row: Option<Point> = None;
19373        if ranges.len() > count {
19374            return Vec::new();
19375        }
19376        for range in &ranges[start_ix..] {
19377            if range
19378                .start
19379                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19380                .is_ge()
19381            {
19382                break;
19383            }
19384            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19385            if let Some(current_row) = &end_row {
19386                if end.row == current_row.row {
19387                    continue;
19388                }
19389            }
19390            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19391            if start_row.is_none() {
19392                assert_eq!(end_row, None);
19393                start_row = Some(start);
19394                end_row = Some(end);
19395                continue;
19396            }
19397            if let Some(current_end) = end_row.as_mut() {
19398                if start.row > current_end.row + 1 {
19399                    push_region(start_row, end_row);
19400                    start_row = Some(start);
19401                    end_row = Some(end);
19402                } else {
19403                    // Merge two hunks.
19404                    *current_end = end;
19405                }
19406            } else {
19407                unreachable!();
19408            }
19409        }
19410        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19411        push_region(start_row, end_row);
19412        results
19413    }
19414
19415    pub fn gutter_highlights_in_range(
19416        &self,
19417        search_range: Range<Anchor>,
19418        display_snapshot: &DisplaySnapshot,
19419        cx: &App,
19420    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19421        let mut results = Vec::new();
19422        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19423            let color = color_fetcher(cx);
19424            let start_ix = match ranges.binary_search_by(|probe| {
19425                let cmp = probe
19426                    .end
19427                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19428                if cmp.is_gt() {
19429                    Ordering::Greater
19430                } else {
19431                    Ordering::Less
19432                }
19433            }) {
19434                Ok(i) | Err(i) => i,
19435            };
19436            for range in &ranges[start_ix..] {
19437                if range
19438                    .start
19439                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19440                    .is_ge()
19441                {
19442                    break;
19443                }
19444
19445                let start = range.start.to_display_point(display_snapshot);
19446                let end = range.end.to_display_point(display_snapshot);
19447                results.push((start..end, color))
19448            }
19449        }
19450        results
19451    }
19452
19453    /// Get the text ranges corresponding to the redaction query
19454    pub fn redacted_ranges(
19455        &self,
19456        search_range: Range<Anchor>,
19457        display_snapshot: &DisplaySnapshot,
19458        cx: &App,
19459    ) -> Vec<Range<DisplayPoint>> {
19460        display_snapshot
19461            .buffer_snapshot
19462            .redacted_ranges(search_range, |file| {
19463                if let Some(file) = file {
19464                    file.is_private()
19465                        && EditorSettings::get(
19466                            Some(SettingsLocation {
19467                                worktree_id: file.worktree_id(cx),
19468                                path: file.path().as_ref(),
19469                            }),
19470                            cx,
19471                        )
19472                        .redact_private_values
19473                } else {
19474                    false
19475                }
19476            })
19477            .map(|range| {
19478                range.start.to_display_point(display_snapshot)
19479                    ..range.end.to_display_point(display_snapshot)
19480            })
19481            .collect()
19482    }
19483
19484    pub fn highlight_text_key<T: 'static>(
19485        &mut self,
19486        key: usize,
19487        ranges: Vec<Range<Anchor>>,
19488        style: HighlightStyle,
19489        cx: &mut Context<Self>,
19490    ) {
19491        self.display_map.update(cx, |map, _| {
19492            map.highlight_text(
19493                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19494                ranges,
19495                style,
19496            );
19497        });
19498        cx.notify();
19499    }
19500
19501    pub fn highlight_text<T: 'static>(
19502        &mut self,
19503        ranges: Vec<Range<Anchor>>,
19504        style: HighlightStyle,
19505        cx: &mut Context<Self>,
19506    ) {
19507        self.display_map.update(cx, |map, _| {
19508            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19509        });
19510        cx.notify();
19511    }
19512
19513    pub(crate) fn highlight_inlays<T: 'static>(
19514        &mut self,
19515        highlights: Vec<InlayHighlight>,
19516        style: HighlightStyle,
19517        cx: &mut Context<Self>,
19518    ) {
19519        self.display_map.update(cx, |map, _| {
19520            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19521        });
19522        cx.notify();
19523    }
19524
19525    pub fn text_highlights<'a, T: 'static>(
19526        &'a self,
19527        cx: &'a App,
19528    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19529        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19530    }
19531
19532    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19533        let cleared = self
19534            .display_map
19535            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19536        if cleared {
19537            cx.notify();
19538        }
19539    }
19540
19541    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19542        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19543            && self.focus_handle.is_focused(window)
19544    }
19545
19546    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19547        self.show_cursor_when_unfocused = is_enabled;
19548        cx.notify();
19549    }
19550
19551    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19552        cx.notify();
19553    }
19554
19555    fn on_debug_session_event(
19556        &mut self,
19557        _session: Entity<Session>,
19558        event: &SessionEvent,
19559        cx: &mut Context<Self>,
19560    ) {
19561        match event {
19562            SessionEvent::InvalidateInlineValue => {
19563                self.refresh_inline_values(cx);
19564            }
19565            _ => {}
19566        }
19567    }
19568
19569    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19570        let Some(project) = self.project.clone() else {
19571            return;
19572        };
19573
19574        if !self.inline_value_cache.enabled {
19575            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19576            self.splice_inlays(&inlays, Vec::new(), cx);
19577            return;
19578        }
19579
19580        let current_execution_position = self
19581            .highlighted_rows
19582            .get(&TypeId::of::<ActiveDebugLine>())
19583            .and_then(|lines| lines.last().map(|line| line.range.end));
19584
19585        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19586            let inline_values = editor
19587                .update(cx, |editor, cx| {
19588                    let Some(current_execution_position) = current_execution_position else {
19589                        return Some(Task::ready(Ok(Vec::new())));
19590                    };
19591
19592                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19593                        let snapshot = buffer.snapshot(cx);
19594
19595                        let excerpt = snapshot.excerpt_containing(
19596                            current_execution_position..current_execution_position,
19597                        )?;
19598
19599                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19600                    })?;
19601
19602                    let range =
19603                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19604
19605                    project.inline_values(buffer, range, cx)
19606                })
19607                .ok()
19608                .flatten()?
19609                .await
19610                .context("refreshing debugger inlays")
19611                .log_err()?;
19612
19613            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19614
19615            for (buffer_id, inline_value) in inline_values
19616                .into_iter()
19617                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19618            {
19619                buffer_inline_values
19620                    .entry(buffer_id)
19621                    .or_default()
19622                    .push(inline_value);
19623            }
19624
19625            editor
19626                .update(cx, |editor, cx| {
19627                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19628                    let mut new_inlays = Vec::default();
19629
19630                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19631                        let buffer_id = buffer_snapshot.remote_id();
19632                        buffer_inline_values
19633                            .get(&buffer_id)
19634                            .into_iter()
19635                            .flatten()
19636                            .for_each(|hint| {
19637                                let inlay = Inlay::debugger(
19638                                    post_inc(&mut editor.next_inlay_id),
19639                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19640                                    hint.text(),
19641                                );
19642
19643                                new_inlays.push(inlay);
19644                            });
19645                    }
19646
19647                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19648                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19649
19650                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19651                })
19652                .ok()?;
19653            Some(())
19654        });
19655    }
19656
19657    fn on_buffer_event(
19658        &mut self,
19659        multibuffer: &Entity<MultiBuffer>,
19660        event: &multi_buffer::Event,
19661        window: &mut Window,
19662        cx: &mut Context<Self>,
19663    ) {
19664        match event {
19665            multi_buffer::Event::Edited {
19666                singleton_buffer_edited,
19667                edited_buffer,
19668            } => {
19669                self.scrollbar_marker_state.dirty = true;
19670                self.active_indent_guides_state.dirty = true;
19671                self.refresh_active_diagnostics(cx);
19672                self.refresh_code_actions(window, cx);
19673                self.refresh_selected_text_highlights(true, window, cx);
19674                self.refresh_single_line_folds(window, cx);
19675                refresh_matching_bracket_highlights(self, window, cx);
19676                if self.has_active_inline_completion() {
19677                    self.update_visible_inline_completion(window, cx);
19678                }
19679                if let Some(project) = self.project.as_ref() {
19680                    if let Some(edited_buffer) = edited_buffer {
19681                        project.update(cx, |project, cx| {
19682                            self.registered_buffers
19683                                .entry(edited_buffer.read(cx).remote_id())
19684                                .or_insert_with(|| {
19685                                    project
19686                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19687                                });
19688                        });
19689                    }
19690                }
19691                cx.emit(EditorEvent::BufferEdited);
19692                cx.emit(SearchEvent::MatchesInvalidated);
19693
19694                if let Some(buffer) = edited_buffer {
19695                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19696                }
19697
19698                if *singleton_buffer_edited {
19699                    if let Some(buffer) = edited_buffer {
19700                        if buffer.read(cx).file().is_none() {
19701                            cx.emit(EditorEvent::TitleChanged);
19702                        }
19703                    }
19704                    if let Some(project) = &self.project {
19705                        #[allow(clippy::mutable_key_type)]
19706                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19707                            multibuffer
19708                                .all_buffers()
19709                                .into_iter()
19710                                .filter_map(|buffer| {
19711                                    buffer.update(cx, |buffer, cx| {
19712                                        let language = buffer.language()?;
19713                                        let should_discard = project.update(cx, |project, cx| {
19714                                            project.is_local()
19715                                                && !project.has_language_servers_for(buffer, cx)
19716                                        });
19717                                        should_discard.not().then_some(language.clone())
19718                                    })
19719                                })
19720                                .collect::<HashSet<_>>()
19721                        });
19722                        if !languages_affected.is_empty() {
19723                            self.refresh_inlay_hints(
19724                                InlayHintRefreshReason::BufferEdited(languages_affected),
19725                                cx,
19726                            );
19727                        }
19728                    }
19729                }
19730
19731                let Some(project) = &self.project else { return };
19732                let (telemetry, is_via_ssh) = {
19733                    let project = project.read(cx);
19734                    let telemetry = project.client().telemetry().clone();
19735                    let is_via_ssh = project.is_via_ssh();
19736                    (telemetry, is_via_ssh)
19737                };
19738                refresh_linked_ranges(self, window, cx);
19739                telemetry.log_edit_event("editor", is_via_ssh);
19740            }
19741            multi_buffer::Event::ExcerptsAdded {
19742                buffer,
19743                predecessor,
19744                excerpts,
19745            } => {
19746                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19747                let buffer_id = buffer.read(cx).remote_id();
19748                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19749                    if let Some(project) = &self.project {
19750                        update_uncommitted_diff_for_buffer(
19751                            cx.entity(),
19752                            project,
19753                            [buffer.clone()],
19754                            self.buffer.clone(),
19755                            cx,
19756                        )
19757                        .detach();
19758                    }
19759                }
19760                self.update_lsp_data(false, Some(buffer_id), window, cx);
19761                cx.emit(EditorEvent::ExcerptsAdded {
19762                    buffer: buffer.clone(),
19763                    predecessor: *predecessor,
19764                    excerpts: excerpts.clone(),
19765                });
19766                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19767            }
19768            multi_buffer::Event::ExcerptsRemoved {
19769                ids,
19770                removed_buffer_ids,
19771            } => {
19772                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19773                let buffer = self.buffer.read(cx);
19774                self.registered_buffers
19775                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19776                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19777                cx.emit(EditorEvent::ExcerptsRemoved {
19778                    ids: ids.clone(),
19779                    removed_buffer_ids: removed_buffer_ids.clone(),
19780                });
19781            }
19782            multi_buffer::Event::ExcerptsEdited {
19783                excerpt_ids,
19784                buffer_ids,
19785            } => {
19786                self.display_map.update(cx, |map, cx| {
19787                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19788                });
19789                cx.emit(EditorEvent::ExcerptsEdited {
19790                    ids: excerpt_ids.clone(),
19791                });
19792            }
19793            multi_buffer::Event::ExcerptsExpanded { ids } => {
19794                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19795                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19796            }
19797            multi_buffer::Event::Reparsed(buffer_id) => {
19798                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19799                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19800
19801                cx.emit(EditorEvent::Reparsed(*buffer_id));
19802            }
19803            multi_buffer::Event::DiffHunksToggled => {
19804                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19805            }
19806            multi_buffer::Event::LanguageChanged(buffer_id) => {
19807                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19808                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19809                cx.emit(EditorEvent::Reparsed(*buffer_id));
19810                cx.notify();
19811            }
19812            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19813            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19814            multi_buffer::Event::FileHandleChanged
19815            | multi_buffer::Event::Reloaded
19816            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19817            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19818            multi_buffer::Event::DiagnosticsUpdated => {
19819                self.update_diagnostics_state(window, cx);
19820            }
19821            _ => {}
19822        };
19823    }
19824
19825    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19826        if !self.diagnostics_enabled() {
19827            return;
19828        }
19829        self.refresh_active_diagnostics(cx);
19830        self.refresh_inline_diagnostics(true, window, cx);
19831        self.scrollbar_marker_state.dirty = true;
19832        cx.notify();
19833    }
19834
19835    pub fn start_temporary_diff_override(&mut self) {
19836        self.load_diff_task.take();
19837        self.temporary_diff_override = true;
19838    }
19839
19840    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19841        self.temporary_diff_override = false;
19842        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19843        self.buffer.update(cx, |buffer, cx| {
19844            buffer.set_all_diff_hunks_collapsed(cx);
19845        });
19846
19847        if let Some(project) = self.project.clone() {
19848            self.load_diff_task = Some(
19849                update_uncommitted_diff_for_buffer(
19850                    cx.entity(),
19851                    &project,
19852                    self.buffer.read(cx).all_buffers(),
19853                    self.buffer.clone(),
19854                    cx,
19855                )
19856                .shared(),
19857            );
19858        }
19859    }
19860
19861    fn on_display_map_changed(
19862        &mut self,
19863        _: Entity<DisplayMap>,
19864        _: &mut Window,
19865        cx: &mut Context<Self>,
19866    ) {
19867        cx.notify();
19868    }
19869
19870    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19871        let new_severity = if self.diagnostics_enabled() {
19872            EditorSettings::get_global(cx)
19873                .diagnostics_max_severity
19874                .unwrap_or(DiagnosticSeverity::Hint)
19875        } else {
19876            DiagnosticSeverity::Off
19877        };
19878        self.set_max_diagnostics_severity(new_severity, cx);
19879        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19880        self.update_edit_prediction_settings(cx);
19881        self.refresh_inline_completion(true, false, window, cx);
19882        self.refresh_inline_values(cx);
19883        self.refresh_inlay_hints(
19884            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19885                self.selections.newest_anchor().head(),
19886                &self.buffer.read(cx).snapshot(cx),
19887                cx,
19888            )),
19889            cx,
19890        );
19891
19892        let old_cursor_shape = self.cursor_shape;
19893
19894        {
19895            let editor_settings = EditorSettings::get_global(cx);
19896            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19897            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19898            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19899            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19900        }
19901
19902        if old_cursor_shape != self.cursor_shape {
19903            cx.emit(EditorEvent::CursorShapeChanged);
19904        }
19905
19906        let project_settings = ProjectSettings::get_global(cx);
19907        self.serialize_dirty_buffers =
19908            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19909
19910        if self.mode.is_full() {
19911            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19912            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19913            if self.show_inline_diagnostics != show_inline_diagnostics {
19914                self.show_inline_diagnostics = show_inline_diagnostics;
19915                self.refresh_inline_diagnostics(false, window, cx);
19916            }
19917
19918            if self.git_blame_inline_enabled != inline_blame_enabled {
19919                self.toggle_git_blame_inline_internal(false, window, cx);
19920            }
19921
19922            let minimap_settings = EditorSettings::get_global(cx).minimap;
19923            if self.minimap_visibility != MinimapVisibility::Disabled {
19924                if self.minimap_visibility.settings_visibility()
19925                    != minimap_settings.minimap_enabled()
19926                {
19927                    self.set_minimap_visibility(
19928                        MinimapVisibility::for_mode(self.mode(), cx),
19929                        window,
19930                        cx,
19931                    );
19932                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19933                    minimap_entity.update(cx, |minimap_editor, cx| {
19934                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19935                    })
19936                }
19937            }
19938        }
19939
19940        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19941            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19942        }) {
19943            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19944                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19945            }
19946            self.refresh_colors(false, None, window, cx);
19947        }
19948
19949        cx.notify();
19950    }
19951
19952    pub fn set_searchable(&mut self, searchable: bool) {
19953        self.searchable = searchable;
19954    }
19955
19956    pub fn searchable(&self) -> bool {
19957        self.searchable
19958    }
19959
19960    fn open_proposed_changes_editor(
19961        &mut self,
19962        _: &OpenProposedChangesEditor,
19963        window: &mut Window,
19964        cx: &mut Context<Self>,
19965    ) {
19966        let Some(workspace) = self.workspace() else {
19967            cx.propagate();
19968            return;
19969        };
19970
19971        let selections = self.selections.all::<usize>(cx);
19972        let multi_buffer = self.buffer.read(cx);
19973        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19974        let mut new_selections_by_buffer = HashMap::default();
19975        for selection in selections {
19976            for (buffer, range, _) in
19977                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19978            {
19979                let mut range = range.to_point(buffer);
19980                range.start.column = 0;
19981                range.end.column = buffer.line_len(range.end.row);
19982                new_selections_by_buffer
19983                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19984                    .or_insert(Vec::new())
19985                    .push(range)
19986            }
19987        }
19988
19989        let proposed_changes_buffers = new_selections_by_buffer
19990            .into_iter()
19991            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19992            .collect::<Vec<_>>();
19993        let proposed_changes_editor = cx.new(|cx| {
19994            ProposedChangesEditor::new(
19995                "Proposed changes",
19996                proposed_changes_buffers,
19997                self.project.clone(),
19998                window,
19999                cx,
20000            )
20001        });
20002
20003        window.defer(cx, move |window, cx| {
20004            workspace.update(cx, |workspace, cx| {
20005                workspace.active_pane().update(cx, |pane, cx| {
20006                    pane.add_item(
20007                        Box::new(proposed_changes_editor),
20008                        true,
20009                        true,
20010                        None,
20011                        window,
20012                        cx,
20013                    );
20014                });
20015            });
20016        });
20017    }
20018
20019    pub fn open_excerpts_in_split(
20020        &mut self,
20021        _: &OpenExcerptsSplit,
20022        window: &mut Window,
20023        cx: &mut Context<Self>,
20024    ) {
20025        self.open_excerpts_common(None, true, window, cx)
20026    }
20027
20028    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20029        self.open_excerpts_common(None, false, window, cx)
20030    }
20031
20032    fn open_excerpts_common(
20033        &mut self,
20034        jump_data: Option<JumpData>,
20035        split: bool,
20036        window: &mut Window,
20037        cx: &mut Context<Self>,
20038    ) {
20039        let Some(workspace) = self.workspace() else {
20040            cx.propagate();
20041            return;
20042        };
20043
20044        if self.buffer.read(cx).is_singleton() {
20045            cx.propagate();
20046            return;
20047        }
20048
20049        let mut new_selections_by_buffer = HashMap::default();
20050        match &jump_data {
20051            Some(JumpData::MultiBufferPoint {
20052                excerpt_id,
20053                position,
20054                anchor,
20055                line_offset_from_top,
20056            }) => {
20057                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20058                if let Some(buffer) = multi_buffer_snapshot
20059                    .buffer_id_for_excerpt(*excerpt_id)
20060                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20061                {
20062                    let buffer_snapshot = buffer.read(cx).snapshot();
20063                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20064                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20065                    } else {
20066                        buffer_snapshot.clip_point(*position, Bias::Left)
20067                    };
20068                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20069                    new_selections_by_buffer.insert(
20070                        buffer,
20071                        (
20072                            vec![jump_to_offset..jump_to_offset],
20073                            Some(*line_offset_from_top),
20074                        ),
20075                    );
20076                }
20077            }
20078            Some(JumpData::MultiBufferRow {
20079                row,
20080                line_offset_from_top,
20081            }) => {
20082                let point = MultiBufferPoint::new(row.0, 0);
20083                if let Some((buffer, buffer_point, _)) =
20084                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20085                {
20086                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20087                    new_selections_by_buffer
20088                        .entry(buffer)
20089                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20090                        .0
20091                        .push(buffer_offset..buffer_offset)
20092                }
20093            }
20094            None => {
20095                let selections = self.selections.all::<usize>(cx);
20096                let multi_buffer = self.buffer.read(cx);
20097                for selection in selections {
20098                    for (snapshot, range, _, anchor) in multi_buffer
20099                        .snapshot(cx)
20100                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20101                    {
20102                        if let Some(anchor) = anchor {
20103                            // selection is in a deleted hunk
20104                            let Some(buffer_id) = anchor.buffer_id else {
20105                                continue;
20106                            };
20107                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20108                                continue;
20109                            };
20110                            let offset = text::ToOffset::to_offset(
20111                                &anchor.text_anchor,
20112                                &buffer_handle.read(cx).snapshot(),
20113                            );
20114                            let range = offset..offset;
20115                            new_selections_by_buffer
20116                                .entry(buffer_handle)
20117                                .or_insert((Vec::new(), None))
20118                                .0
20119                                .push(range)
20120                        } else {
20121                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20122                            else {
20123                                continue;
20124                            };
20125                            new_selections_by_buffer
20126                                .entry(buffer_handle)
20127                                .or_insert((Vec::new(), None))
20128                                .0
20129                                .push(range)
20130                        }
20131                    }
20132                }
20133            }
20134        }
20135
20136        new_selections_by_buffer
20137            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20138
20139        if new_selections_by_buffer.is_empty() {
20140            return;
20141        }
20142
20143        // We defer the pane interaction because we ourselves are a workspace item
20144        // and activating a new item causes the pane to call a method on us reentrantly,
20145        // which panics if we're on the stack.
20146        window.defer(cx, move |window, cx| {
20147            workspace.update(cx, |workspace, cx| {
20148                let pane = if split {
20149                    workspace.adjacent_pane(window, cx)
20150                } else {
20151                    workspace.active_pane().clone()
20152                };
20153
20154                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20155                    let editor = buffer
20156                        .read(cx)
20157                        .file()
20158                        .is_none()
20159                        .then(|| {
20160                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20161                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20162                            // Instead, we try to activate the existing editor in the pane first.
20163                            let (editor, pane_item_index) =
20164                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20165                                    let editor = item.downcast::<Editor>()?;
20166                                    let singleton_buffer =
20167                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20168                                    if singleton_buffer == buffer {
20169                                        Some((editor, i))
20170                                    } else {
20171                                        None
20172                                    }
20173                                })?;
20174                            pane.update(cx, |pane, cx| {
20175                                pane.activate_item(pane_item_index, true, true, window, cx)
20176                            });
20177                            Some(editor)
20178                        })
20179                        .flatten()
20180                        .unwrap_or_else(|| {
20181                            workspace.open_project_item::<Self>(
20182                                pane.clone(),
20183                                buffer,
20184                                true,
20185                                true,
20186                                window,
20187                                cx,
20188                            )
20189                        });
20190
20191                    editor.update(cx, |editor, cx| {
20192                        let autoscroll = match scroll_offset {
20193                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20194                            None => Autoscroll::newest(),
20195                        };
20196                        let nav_history = editor.nav_history.take();
20197                        editor.change_selections(
20198                            SelectionEffects::scroll(autoscroll),
20199                            window,
20200                            cx,
20201                            |s| {
20202                                s.select_ranges(ranges);
20203                            },
20204                        );
20205                        editor.nav_history = nav_history;
20206                    });
20207                }
20208            })
20209        });
20210    }
20211
20212    // For now, don't allow opening excerpts in buffers that aren't backed by
20213    // regular project files.
20214    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20215        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20216    }
20217
20218    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20219        let snapshot = self.buffer.read(cx).read(cx);
20220        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20221        Some(
20222            ranges
20223                .iter()
20224                .map(move |range| {
20225                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20226                })
20227                .collect(),
20228        )
20229    }
20230
20231    fn selection_replacement_ranges(
20232        &self,
20233        range: Range<OffsetUtf16>,
20234        cx: &mut App,
20235    ) -> Vec<Range<OffsetUtf16>> {
20236        let selections = self.selections.all::<OffsetUtf16>(cx);
20237        let newest_selection = selections
20238            .iter()
20239            .max_by_key(|selection| selection.id)
20240            .unwrap();
20241        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20242        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20243        let snapshot = self.buffer.read(cx).read(cx);
20244        selections
20245            .into_iter()
20246            .map(|mut selection| {
20247                selection.start.0 =
20248                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20249                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20250                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20251                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20252            })
20253            .collect()
20254    }
20255
20256    fn report_editor_event(
20257        &self,
20258        event_type: &'static str,
20259        file_extension: Option<String>,
20260        cx: &App,
20261    ) {
20262        if cfg!(any(test, feature = "test-support")) {
20263            return;
20264        }
20265
20266        let Some(project) = &self.project else { return };
20267
20268        // If None, we are in a file without an extension
20269        let file = self
20270            .buffer
20271            .read(cx)
20272            .as_singleton()
20273            .and_then(|b| b.read(cx).file());
20274        let file_extension = file_extension.or(file
20275            .as_ref()
20276            .and_then(|file| Path::new(file.file_name(cx)).extension())
20277            .and_then(|e| e.to_str())
20278            .map(|a| a.to_string()));
20279
20280        let vim_mode = vim_enabled(cx);
20281
20282        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20283        let copilot_enabled = edit_predictions_provider
20284            == language::language_settings::EditPredictionProvider::Copilot;
20285        let copilot_enabled_for_language = self
20286            .buffer
20287            .read(cx)
20288            .language_settings(cx)
20289            .show_edit_predictions;
20290
20291        let project = project.read(cx);
20292        telemetry::event!(
20293            event_type,
20294            file_extension,
20295            vim_mode,
20296            copilot_enabled,
20297            copilot_enabled_for_language,
20298            edit_predictions_provider,
20299            is_via_ssh = project.is_via_ssh(),
20300        );
20301    }
20302
20303    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20304    /// with each line being an array of {text, highlight} objects.
20305    fn copy_highlight_json(
20306        &mut self,
20307        _: &CopyHighlightJson,
20308        window: &mut Window,
20309        cx: &mut Context<Self>,
20310    ) {
20311        #[derive(Serialize)]
20312        struct Chunk<'a> {
20313            text: String,
20314            highlight: Option<&'a str>,
20315        }
20316
20317        let snapshot = self.buffer.read(cx).snapshot(cx);
20318        let range = self
20319            .selected_text_range(false, window, cx)
20320            .and_then(|selection| {
20321                if selection.range.is_empty() {
20322                    None
20323                } else {
20324                    Some(selection.range)
20325                }
20326            })
20327            .unwrap_or_else(|| 0..snapshot.len());
20328
20329        let chunks = snapshot.chunks(range, true);
20330        let mut lines = Vec::new();
20331        let mut line: VecDeque<Chunk> = VecDeque::new();
20332
20333        let Some(style) = self.style.as_ref() else {
20334            return;
20335        };
20336
20337        for chunk in chunks {
20338            let highlight = chunk
20339                .syntax_highlight_id
20340                .and_then(|id| id.name(&style.syntax));
20341            let mut chunk_lines = chunk.text.split('\n').peekable();
20342            while let Some(text) = chunk_lines.next() {
20343                let mut merged_with_last_token = false;
20344                if let Some(last_token) = line.back_mut() {
20345                    if last_token.highlight == highlight {
20346                        last_token.text.push_str(text);
20347                        merged_with_last_token = true;
20348                    }
20349                }
20350
20351                if !merged_with_last_token {
20352                    line.push_back(Chunk {
20353                        text: text.into(),
20354                        highlight,
20355                    });
20356                }
20357
20358                if chunk_lines.peek().is_some() {
20359                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20360                        line.pop_front();
20361                    }
20362                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20363                        line.pop_back();
20364                    }
20365
20366                    lines.push(mem::take(&mut line));
20367                }
20368            }
20369        }
20370
20371        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20372            return;
20373        };
20374        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20375    }
20376
20377    pub fn open_context_menu(
20378        &mut self,
20379        _: &OpenContextMenu,
20380        window: &mut Window,
20381        cx: &mut Context<Self>,
20382    ) {
20383        self.request_autoscroll(Autoscroll::newest(), cx);
20384        let position = self.selections.newest_display(cx).start;
20385        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20386    }
20387
20388    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20389        &self.inlay_hint_cache
20390    }
20391
20392    pub fn replay_insert_event(
20393        &mut self,
20394        text: &str,
20395        relative_utf16_range: Option<Range<isize>>,
20396        window: &mut Window,
20397        cx: &mut Context<Self>,
20398    ) {
20399        if !self.input_enabled {
20400            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20401            return;
20402        }
20403        if let Some(relative_utf16_range) = relative_utf16_range {
20404            let selections = self.selections.all::<OffsetUtf16>(cx);
20405            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20406                let new_ranges = selections.into_iter().map(|range| {
20407                    let start = OffsetUtf16(
20408                        range
20409                            .head()
20410                            .0
20411                            .saturating_add_signed(relative_utf16_range.start),
20412                    );
20413                    let end = OffsetUtf16(
20414                        range
20415                            .head()
20416                            .0
20417                            .saturating_add_signed(relative_utf16_range.end),
20418                    );
20419                    start..end
20420                });
20421                s.select_ranges(new_ranges);
20422            });
20423        }
20424
20425        self.handle_input(text, window, cx);
20426    }
20427
20428    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20429        let Some(provider) = self.semantics_provider.as_ref() else {
20430            return false;
20431        };
20432
20433        let mut supports = false;
20434        self.buffer().update(cx, |this, cx| {
20435            this.for_each_buffer(|buffer| {
20436                supports |= provider.supports_inlay_hints(buffer, cx);
20437            });
20438        });
20439
20440        supports
20441    }
20442
20443    pub fn is_focused(&self, window: &Window) -> bool {
20444        self.focus_handle.is_focused(window)
20445    }
20446
20447    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20448        cx.emit(EditorEvent::Focused);
20449
20450        if let Some(descendant) = self
20451            .last_focused_descendant
20452            .take()
20453            .and_then(|descendant| descendant.upgrade())
20454        {
20455            window.focus(&descendant);
20456        } else {
20457            if let Some(blame) = self.blame.as_ref() {
20458                blame.update(cx, GitBlame::focus)
20459            }
20460
20461            self.blink_manager.update(cx, BlinkManager::enable);
20462            self.show_cursor_names(window, cx);
20463            self.buffer.update(cx, |buffer, cx| {
20464                buffer.finalize_last_transaction(cx);
20465                if self.leader_id.is_none() {
20466                    buffer.set_active_selections(
20467                        &self.selections.disjoint_anchors(),
20468                        self.selections.line_mode,
20469                        self.cursor_shape,
20470                        cx,
20471                    );
20472                }
20473            });
20474        }
20475    }
20476
20477    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20478        cx.emit(EditorEvent::FocusedIn)
20479    }
20480
20481    fn handle_focus_out(
20482        &mut self,
20483        event: FocusOutEvent,
20484        _window: &mut Window,
20485        cx: &mut Context<Self>,
20486    ) {
20487        if event.blurred != self.focus_handle {
20488            self.last_focused_descendant = Some(event.blurred);
20489        }
20490        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20491    }
20492
20493    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20494        self.blink_manager.update(cx, BlinkManager::disable);
20495        self.buffer
20496            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20497
20498        if let Some(blame) = self.blame.as_ref() {
20499            blame.update(cx, GitBlame::blur)
20500        }
20501        if !self.hover_state.focused(window, cx) {
20502            hide_hover(self, cx);
20503        }
20504        if !self
20505            .context_menu
20506            .borrow()
20507            .as_ref()
20508            .is_some_and(|context_menu| context_menu.focused(window, cx))
20509        {
20510            self.hide_context_menu(window, cx);
20511        }
20512        self.discard_inline_completion(false, cx);
20513        cx.emit(EditorEvent::Blurred);
20514        cx.notify();
20515    }
20516
20517    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20518        let mut pending: String = window
20519            .pending_input_keystrokes()
20520            .into_iter()
20521            .flatten()
20522            .filter_map(|keystroke| {
20523                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20524                    keystroke.key_char.clone()
20525                } else {
20526                    None
20527                }
20528            })
20529            .collect();
20530
20531        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20532            pending = "".to_string();
20533        }
20534
20535        let existing_pending = self
20536            .text_highlights::<PendingInput>(cx)
20537            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20538        if existing_pending.is_none() && pending.is_empty() {
20539            return;
20540        }
20541        let transaction =
20542            self.transact(window, cx, |this, window, cx| {
20543                let selections = this.selections.all::<usize>(cx);
20544                let edits = selections
20545                    .iter()
20546                    .map(|selection| (selection.end..selection.end, pending.clone()));
20547                this.edit(edits, cx);
20548                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20549                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20550                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20551                    }));
20552                });
20553                if let Some(existing_ranges) = existing_pending {
20554                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20555                    this.edit(edits, cx);
20556                }
20557            });
20558
20559        let snapshot = self.snapshot(window, cx);
20560        let ranges = self
20561            .selections
20562            .all::<usize>(cx)
20563            .into_iter()
20564            .map(|selection| {
20565                snapshot.buffer_snapshot.anchor_after(selection.end)
20566                    ..snapshot
20567                        .buffer_snapshot
20568                        .anchor_before(selection.end + pending.len())
20569            })
20570            .collect();
20571
20572        if pending.is_empty() {
20573            self.clear_highlights::<PendingInput>(cx);
20574        } else {
20575            self.highlight_text::<PendingInput>(
20576                ranges,
20577                HighlightStyle {
20578                    underline: Some(UnderlineStyle {
20579                        thickness: px(1.),
20580                        color: None,
20581                        wavy: false,
20582                    }),
20583                    ..Default::default()
20584                },
20585                cx,
20586            );
20587        }
20588
20589        self.ime_transaction = self.ime_transaction.or(transaction);
20590        if let Some(transaction) = self.ime_transaction {
20591            self.buffer.update(cx, |buffer, cx| {
20592                buffer.group_until_transaction(transaction, cx);
20593            });
20594        }
20595
20596        if self.text_highlights::<PendingInput>(cx).is_none() {
20597            self.ime_transaction.take();
20598        }
20599    }
20600
20601    pub fn register_action_renderer(
20602        &mut self,
20603        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20604    ) -> Subscription {
20605        let id = self.next_editor_action_id.post_inc();
20606        self.editor_actions
20607            .borrow_mut()
20608            .insert(id, Box::new(listener));
20609
20610        let editor_actions = self.editor_actions.clone();
20611        Subscription::new(move || {
20612            editor_actions.borrow_mut().remove(&id);
20613        })
20614    }
20615
20616    pub fn register_action<A: Action>(
20617        &mut self,
20618        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20619    ) -> Subscription {
20620        let id = self.next_editor_action_id.post_inc();
20621        let listener = Arc::new(listener);
20622        self.editor_actions.borrow_mut().insert(
20623            id,
20624            Box::new(move |_, window, _| {
20625                let listener = listener.clone();
20626                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20627                    let action = action.downcast_ref().unwrap();
20628                    if phase == DispatchPhase::Bubble {
20629                        listener(action, window, cx)
20630                    }
20631                })
20632            }),
20633        );
20634
20635        let editor_actions = self.editor_actions.clone();
20636        Subscription::new(move || {
20637            editor_actions.borrow_mut().remove(&id);
20638        })
20639    }
20640
20641    pub fn file_header_size(&self) -> u32 {
20642        FILE_HEADER_HEIGHT
20643    }
20644
20645    pub fn restore(
20646        &mut self,
20647        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20648        window: &mut Window,
20649        cx: &mut Context<Self>,
20650    ) {
20651        let workspace = self.workspace();
20652        let project = self.project.as_ref();
20653        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20654            let mut tasks = Vec::new();
20655            for (buffer_id, changes) in revert_changes {
20656                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20657                    buffer.update(cx, |buffer, cx| {
20658                        buffer.edit(
20659                            changes
20660                                .into_iter()
20661                                .map(|(range, text)| (range, text.to_string())),
20662                            None,
20663                            cx,
20664                        );
20665                    });
20666
20667                    if let Some(project) =
20668                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20669                    {
20670                        project.update(cx, |project, cx| {
20671                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20672                        })
20673                    }
20674                }
20675            }
20676            tasks
20677        });
20678        cx.spawn_in(window, async move |_, cx| {
20679            for (buffer, task) in save_tasks {
20680                let result = task.await;
20681                if result.is_err() {
20682                    let Some(path) = buffer
20683                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20684                        .ok()
20685                    else {
20686                        continue;
20687                    };
20688                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20689                        let Some(task) = cx
20690                            .update_window_entity(&workspace, |workspace, window, cx| {
20691                                workspace
20692                                    .open_path_preview(path, None, false, false, false, window, cx)
20693                            })
20694                            .ok()
20695                        else {
20696                            continue;
20697                        };
20698                        task.await.log_err();
20699                    }
20700                }
20701            }
20702        })
20703        .detach();
20704        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20705            selections.refresh()
20706        });
20707    }
20708
20709    pub fn to_pixel_point(
20710        &self,
20711        source: multi_buffer::Anchor,
20712        editor_snapshot: &EditorSnapshot,
20713        window: &mut Window,
20714    ) -> Option<gpui::Point<Pixels>> {
20715        let source_point = source.to_display_point(editor_snapshot);
20716        self.display_to_pixel_point(source_point, editor_snapshot, window)
20717    }
20718
20719    pub fn display_to_pixel_point(
20720        &self,
20721        source: DisplayPoint,
20722        editor_snapshot: &EditorSnapshot,
20723        window: &mut Window,
20724    ) -> Option<gpui::Point<Pixels>> {
20725        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20726        let text_layout_details = self.text_layout_details(window);
20727        let scroll_top = text_layout_details
20728            .scroll_anchor
20729            .scroll_position(editor_snapshot)
20730            .y;
20731
20732        if source.row().as_f32() < scroll_top.floor() {
20733            return None;
20734        }
20735        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20736        let source_y = line_height * (source.row().as_f32() - scroll_top);
20737        Some(gpui::Point::new(source_x, source_y))
20738    }
20739
20740    pub fn has_visible_completions_menu(&self) -> bool {
20741        !self.edit_prediction_preview_is_active()
20742            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20743                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20744            })
20745    }
20746
20747    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20748        if self.mode.is_minimap() {
20749            return;
20750        }
20751        self.addons
20752            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20753    }
20754
20755    pub fn unregister_addon<T: Addon>(&mut self) {
20756        self.addons.remove(&std::any::TypeId::of::<T>());
20757    }
20758
20759    pub fn addon<T: Addon>(&self) -> Option<&T> {
20760        let type_id = std::any::TypeId::of::<T>();
20761        self.addons
20762            .get(&type_id)
20763            .and_then(|item| item.to_any().downcast_ref::<T>())
20764    }
20765
20766    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20767        let type_id = std::any::TypeId::of::<T>();
20768        self.addons
20769            .get_mut(&type_id)
20770            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20771    }
20772
20773    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20774        let text_layout_details = self.text_layout_details(window);
20775        let style = &text_layout_details.editor_style;
20776        let font_id = window.text_system().resolve_font(&style.text.font());
20777        let font_size = style.text.font_size.to_pixels(window.rem_size());
20778        let line_height = style.text.line_height_in_pixels(window.rem_size());
20779        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20780        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20781
20782        CharacterDimensions {
20783            em_width,
20784            em_advance,
20785            line_height,
20786        }
20787    }
20788
20789    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20790        self.load_diff_task.clone()
20791    }
20792
20793    fn read_metadata_from_db(
20794        &mut self,
20795        item_id: u64,
20796        workspace_id: WorkspaceId,
20797        window: &mut Window,
20798        cx: &mut Context<Editor>,
20799    ) {
20800        if self.is_singleton(cx)
20801            && !self.mode.is_minimap()
20802            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20803        {
20804            let buffer_snapshot = OnceCell::new();
20805
20806            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20807                if !folds.is_empty() {
20808                    let snapshot =
20809                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20810                    self.fold_ranges(
20811                        folds
20812                            .into_iter()
20813                            .map(|(start, end)| {
20814                                snapshot.clip_offset(start, Bias::Left)
20815                                    ..snapshot.clip_offset(end, Bias::Right)
20816                            })
20817                            .collect(),
20818                        false,
20819                        window,
20820                        cx,
20821                    );
20822                }
20823            }
20824
20825            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20826                if !selections.is_empty() {
20827                    let snapshot =
20828                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20829                    // skip adding the initial selection to selection history
20830                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20831                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20832                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20833                            snapshot.clip_offset(start, Bias::Left)
20834                                ..snapshot.clip_offset(end, Bias::Right)
20835                        }));
20836                    });
20837                    self.selection_history.mode = SelectionHistoryMode::Normal;
20838                }
20839            };
20840        }
20841
20842        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20843    }
20844
20845    fn update_lsp_data(
20846        &mut self,
20847        ignore_cache: bool,
20848        for_buffer: Option<BufferId>,
20849        window: &mut Window,
20850        cx: &mut Context<'_, Self>,
20851    ) {
20852        self.pull_diagnostics(for_buffer, window, cx);
20853        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20854    }
20855}
20856
20857fn vim_enabled(cx: &App) -> bool {
20858    cx.global::<SettingsStore>()
20859        .raw_user_settings()
20860        .get("vim_mode")
20861        == Some(&serde_json::Value::Bool(true))
20862}
20863
20864fn process_completion_for_edit(
20865    completion: &Completion,
20866    intent: CompletionIntent,
20867    buffer: &Entity<Buffer>,
20868    cursor_position: &text::Anchor,
20869    cx: &mut Context<Editor>,
20870) -> CompletionEdit {
20871    let buffer = buffer.read(cx);
20872    let buffer_snapshot = buffer.snapshot();
20873    let (snippet, new_text) = if completion.is_snippet() {
20874        // Workaround for typescript language server issues so that methods don't expand within
20875        // strings and functions with type expressions. The previous point is used because the query
20876        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20877        let mut snippet_source = completion.new_text.clone();
20878        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20879        previous_point.column = previous_point.column.saturating_sub(1);
20880        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20881            if scope.prefers_label_for_snippet_in_completion() {
20882                if let Some(label) = completion.label() {
20883                    if matches!(
20884                        completion.kind(),
20885                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20886                    ) {
20887                        snippet_source = label;
20888                    }
20889                }
20890            }
20891        }
20892        match Snippet::parse(&snippet_source).log_err() {
20893            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20894            None => (None, completion.new_text.clone()),
20895        }
20896    } else {
20897        (None, completion.new_text.clone())
20898    };
20899
20900    let mut range_to_replace = {
20901        let replace_range = &completion.replace_range;
20902        if let CompletionSource::Lsp {
20903            insert_range: Some(insert_range),
20904            ..
20905        } = &completion.source
20906        {
20907            debug_assert_eq!(
20908                insert_range.start, replace_range.start,
20909                "insert_range and replace_range should start at the same position"
20910            );
20911            debug_assert!(
20912                insert_range
20913                    .start
20914                    .cmp(&cursor_position, &buffer_snapshot)
20915                    .is_le(),
20916                "insert_range should start before or at cursor position"
20917            );
20918            debug_assert!(
20919                replace_range
20920                    .start
20921                    .cmp(&cursor_position, &buffer_snapshot)
20922                    .is_le(),
20923                "replace_range should start before or at cursor position"
20924            );
20925            debug_assert!(
20926                insert_range
20927                    .end
20928                    .cmp(&cursor_position, &buffer_snapshot)
20929                    .is_le(),
20930                "insert_range should end before or at cursor position"
20931            );
20932
20933            let should_replace = match intent {
20934                CompletionIntent::CompleteWithInsert => false,
20935                CompletionIntent::CompleteWithReplace => true,
20936                CompletionIntent::Complete | CompletionIntent::Compose => {
20937                    let insert_mode =
20938                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20939                            .completions
20940                            .lsp_insert_mode;
20941                    match insert_mode {
20942                        LspInsertMode::Insert => false,
20943                        LspInsertMode::Replace => true,
20944                        LspInsertMode::ReplaceSubsequence => {
20945                            let mut text_to_replace = buffer.chars_for_range(
20946                                buffer.anchor_before(replace_range.start)
20947                                    ..buffer.anchor_after(replace_range.end),
20948                            );
20949                            let mut current_needle = text_to_replace.next();
20950                            for haystack_ch in completion.label.text.chars() {
20951                                if let Some(needle_ch) = current_needle {
20952                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20953                                        current_needle = text_to_replace.next();
20954                                    }
20955                                }
20956                            }
20957                            current_needle.is_none()
20958                        }
20959                        LspInsertMode::ReplaceSuffix => {
20960                            if replace_range
20961                                .end
20962                                .cmp(&cursor_position, &buffer_snapshot)
20963                                .is_gt()
20964                            {
20965                                let range_after_cursor = *cursor_position..replace_range.end;
20966                                let text_after_cursor = buffer
20967                                    .text_for_range(
20968                                        buffer.anchor_before(range_after_cursor.start)
20969                                            ..buffer.anchor_after(range_after_cursor.end),
20970                                    )
20971                                    .collect::<String>()
20972                                    .to_ascii_lowercase();
20973                                completion
20974                                    .label
20975                                    .text
20976                                    .to_ascii_lowercase()
20977                                    .ends_with(&text_after_cursor)
20978                            } else {
20979                                true
20980                            }
20981                        }
20982                    }
20983                }
20984            };
20985
20986            if should_replace {
20987                replace_range.clone()
20988            } else {
20989                insert_range.clone()
20990            }
20991        } else {
20992            replace_range.clone()
20993        }
20994    };
20995
20996    if range_to_replace
20997        .end
20998        .cmp(&cursor_position, &buffer_snapshot)
20999        .is_lt()
21000    {
21001        range_to_replace.end = *cursor_position;
21002    }
21003
21004    CompletionEdit {
21005        new_text,
21006        replace_range: range_to_replace.to_offset(&buffer),
21007        snippet,
21008    }
21009}
21010
21011struct CompletionEdit {
21012    new_text: String,
21013    replace_range: Range<usize>,
21014    snippet: Option<Snippet>,
21015}
21016
21017fn insert_extra_newline_brackets(
21018    buffer: &MultiBufferSnapshot,
21019    range: Range<usize>,
21020    language: &language::LanguageScope,
21021) -> bool {
21022    let leading_whitespace_len = buffer
21023        .reversed_chars_at(range.start)
21024        .take_while(|c| c.is_whitespace() && *c != '\n')
21025        .map(|c| c.len_utf8())
21026        .sum::<usize>();
21027    let trailing_whitespace_len = buffer
21028        .chars_at(range.end)
21029        .take_while(|c| c.is_whitespace() && *c != '\n')
21030        .map(|c| c.len_utf8())
21031        .sum::<usize>();
21032    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21033
21034    language.brackets().any(|(pair, enabled)| {
21035        let pair_start = pair.start.trim_end();
21036        let pair_end = pair.end.trim_start();
21037
21038        enabled
21039            && pair.newline
21040            && buffer.contains_str_at(range.end, pair_end)
21041            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21042    })
21043}
21044
21045fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21046    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21047        [(buffer, range, _)] => (*buffer, range.clone()),
21048        _ => return false,
21049    };
21050    let pair = {
21051        let mut result: Option<BracketMatch> = None;
21052
21053        for pair in buffer
21054            .all_bracket_ranges(range.clone())
21055            .filter(move |pair| {
21056                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21057            })
21058        {
21059            let len = pair.close_range.end - pair.open_range.start;
21060
21061            if let Some(existing) = &result {
21062                let existing_len = existing.close_range.end - existing.open_range.start;
21063                if len > existing_len {
21064                    continue;
21065                }
21066            }
21067
21068            result = Some(pair);
21069        }
21070
21071        result
21072    };
21073    let Some(pair) = pair else {
21074        return false;
21075    };
21076    pair.newline_only
21077        && buffer
21078            .chars_for_range(pair.open_range.end..range.start)
21079            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21080            .all(|c| c.is_whitespace() && c != '\n')
21081}
21082
21083fn update_uncommitted_diff_for_buffer(
21084    editor: Entity<Editor>,
21085    project: &Entity<Project>,
21086    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21087    buffer: Entity<MultiBuffer>,
21088    cx: &mut App,
21089) -> Task<()> {
21090    let mut tasks = Vec::new();
21091    project.update(cx, |project, cx| {
21092        for buffer in buffers {
21093            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21094                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21095            }
21096        }
21097    });
21098    cx.spawn(async move |cx| {
21099        let diffs = future::join_all(tasks).await;
21100        if editor
21101            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21102            .unwrap_or(false)
21103        {
21104            return;
21105        }
21106
21107        buffer
21108            .update(cx, |buffer, cx| {
21109                for diff in diffs.into_iter().flatten() {
21110                    buffer.add_diff(diff, cx);
21111                }
21112            })
21113            .ok();
21114    })
21115}
21116
21117fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21118    let tab_size = tab_size.get() as usize;
21119    let mut width = offset;
21120
21121    for ch in text.chars() {
21122        width += if ch == '\t' {
21123            tab_size - (width % tab_size)
21124        } else {
21125            1
21126        };
21127    }
21128
21129    width - offset
21130}
21131
21132#[cfg(test)]
21133mod tests {
21134    use super::*;
21135
21136    #[test]
21137    fn test_string_size_with_expanded_tabs() {
21138        let nz = |val| NonZeroU32::new(val).unwrap();
21139        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21140        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21141        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21142        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21143        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21144        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21145        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21146        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21147    }
21148}
21149
21150/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21151struct WordBreakingTokenizer<'a> {
21152    input: &'a str,
21153}
21154
21155impl<'a> WordBreakingTokenizer<'a> {
21156    fn new(input: &'a str) -> Self {
21157        Self { input }
21158    }
21159}
21160
21161fn is_char_ideographic(ch: char) -> bool {
21162    use unicode_script::Script::*;
21163    use unicode_script::UnicodeScript;
21164    matches!(ch.script(), Han | Tangut | Yi)
21165}
21166
21167fn is_grapheme_ideographic(text: &str) -> bool {
21168    text.chars().any(is_char_ideographic)
21169}
21170
21171fn is_grapheme_whitespace(text: &str) -> bool {
21172    text.chars().any(|x| x.is_whitespace())
21173}
21174
21175fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21176    text.chars().next().map_or(false, |ch| {
21177        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21178    })
21179}
21180
21181#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21182enum WordBreakToken<'a> {
21183    Word { token: &'a str, grapheme_len: usize },
21184    InlineWhitespace { token: &'a str, grapheme_len: usize },
21185    Newline,
21186}
21187
21188impl<'a> Iterator for WordBreakingTokenizer<'a> {
21189    /// Yields a span, the count of graphemes in the token, and whether it was
21190    /// whitespace. Note that it also breaks at word boundaries.
21191    type Item = WordBreakToken<'a>;
21192
21193    fn next(&mut self) -> Option<Self::Item> {
21194        use unicode_segmentation::UnicodeSegmentation;
21195        if self.input.is_empty() {
21196            return None;
21197        }
21198
21199        let mut iter = self.input.graphemes(true).peekable();
21200        let mut offset = 0;
21201        let mut grapheme_len = 0;
21202        if let Some(first_grapheme) = iter.next() {
21203            let is_newline = first_grapheme == "\n";
21204            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21205            offset += first_grapheme.len();
21206            grapheme_len += 1;
21207            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21208                if let Some(grapheme) = iter.peek().copied() {
21209                    if should_stay_with_preceding_ideograph(grapheme) {
21210                        offset += grapheme.len();
21211                        grapheme_len += 1;
21212                    }
21213                }
21214            } else {
21215                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21216                let mut next_word_bound = words.peek().copied();
21217                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21218                    next_word_bound = words.next();
21219                }
21220                while let Some(grapheme) = iter.peek().copied() {
21221                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21222                        break;
21223                    };
21224                    if is_grapheme_whitespace(grapheme) != is_whitespace
21225                        || (grapheme == "\n") != is_newline
21226                    {
21227                        break;
21228                    };
21229                    offset += grapheme.len();
21230                    grapheme_len += 1;
21231                    iter.next();
21232                }
21233            }
21234            let token = &self.input[..offset];
21235            self.input = &self.input[offset..];
21236            if token == "\n" {
21237                Some(WordBreakToken::Newline)
21238            } else if is_whitespace {
21239                Some(WordBreakToken::InlineWhitespace {
21240                    token,
21241                    grapheme_len,
21242                })
21243            } else {
21244                Some(WordBreakToken::Word {
21245                    token,
21246                    grapheme_len,
21247                })
21248            }
21249        } else {
21250            None
21251        }
21252    }
21253}
21254
21255#[test]
21256fn test_word_breaking_tokenizer() {
21257    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21258        ("", &[]),
21259        ("  ", &[whitespace("  ", 2)]),
21260        ("Ʒ", &[word("Ʒ", 1)]),
21261        ("Ǽ", &[word("Ǽ", 1)]),
21262        ("", &[word("", 1)]),
21263        ("⋑⋑", &[word("⋑⋑", 2)]),
21264        (
21265            "原理,进而",
21266            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21267        ),
21268        (
21269            "hello world",
21270            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21271        ),
21272        (
21273            "hello, world",
21274            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21275        ),
21276        (
21277            "  hello world",
21278            &[
21279                whitespace("  ", 2),
21280                word("hello", 5),
21281                whitespace(" ", 1),
21282                word("world", 5),
21283            ],
21284        ),
21285        (
21286            "这是什么 \n 钢笔",
21287            &[
21288                word("", 1),
21289                word("", 1),
21290                word("", 1),
21291                word("", 1),
21292                whitespace(" ", 1),
21293                newline(),
21294                whitespace(" ", 1),
21295                word("", 1),
21296                word("", 1),
21297            ],
21298        ),
21299        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21300    ];
21301
21302    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21303        WordBreakToken::Word {
21304            token,
21305            grapheme_len,
21306        }
21307    }
21308
21309    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21310        WordBreakToken::InlineWhitespace {
21311            token,
21312            grapheme_len,
21313        }
21314    }
21315
21316    fn newline() -> WordBreakToken<'static> {
21317        WordBreakToken::Newline
21318    }
21319
21320    for (input, result) in tests {
21321        assert_eq!(
21322            WordBreakingTokenizer::new(input)
21323                .collect::<Vec<_>>()
21324                .as_slice(),
21325            *result,
21326        );
21327    }
21328}
21329
21330fn wrap_with_prefix(
21331    first_line_prefix: String,
21332    subsequent_lines_prefix: String,
21333    unwrapped_text: String,
21334    wrap_column: usize,
21335    tab_size: NonZeroU32,
21336    preserve_existing_whitespace: bool,
21337) -> String {
21338    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21339    let subsequent_lines_prefix_len =
21340        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21341    let mut wrapped_text = String::new();
21342    let mut current_line = first_line_prefix.clone();
21343    let mut is_first_line = true;
21344
21345    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21346    let mut current_line_len = first_line_prefix_len;
21347    let mut in_whitespace = false;
21348    for token in tokenizer {
21349        let have_preceding_whitespace = in_whitespace;
21350        match token {
21351            WordBreakToken::Word {
21352                token,
21353                grapheme_len,
21354            } => {
21355                in_whitespace = false;
21356                let current_prefix_len = if is_first_line {
21357                    first_line_prefix_len
21358                } else {
21359                    subsequent_lines_prefix_len
21360                };
21361                if current_line_len + grapheme_len > wrap_column
21362                    && current_line_len != current_prefix_len
21363                {
21364                    wrapped_text.push_str(current_line.trim_end());
21365                    wrapped_text.push('\n');
21366                    is_first_line = false;
21367                    current_line = subsequent_lines_prefix.clone();
21368                    current_line_len = subsequent_lines_prefix_len;
21369                }
21370                current_line.push_str(token);
21371                current_line_len += grapheme_len;
21372            }
21373            WordBreakToken::InlineWhitespace {
21374                mut token,
21375                mut grapheme_len,
21376            } => {
21377                in_whitespace = true;
21378                if have_preceding_whitespace && !preserve_existing_whitespace {
21379                    continue;
21380                }
21381                if !preserve_existing_whitespace {
21382                    token = " ";
21383                    grapheme_len = 1;
21384                }
21385                let current_prefix_len = if is_first_line {
21386                    first_line_prefix_len
21387                } else {
21388                    subsequent_lines_prefix_len
21389                };
21390                if current_line_len + grapheme_len > wrap_column {
21391                    wrapped_text.push_str(current_line.trim_end());
21392                    wrapped_text.push('\n');
21393                    is_first_line = false;
21394                    current_line = subsequent_lines_prefix.clone();
21395                    current_line_len = subsequent_lines_prefix_len;
21396                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21397                    current_line.push_str(token);
21398                    current_line_len += grapheme_len;
21399                }
21400            }
21401            WordBreakToken::Newline => {
21402                in_whitespace = true;
21403                let current_prefix_len = if is_first_line {
21404                    first_line_prefix_len
21405                } else {
21406                    subsequent_lines_prefix_len
21407                };
21408                if preserve_existing_whitespace {
21409                    wrapped_text.push_str(current_line.trim_end());
21410                    wrapped_text.push('\n');
21411                    is_first_line = false;
21412                    current_line = subsequent_lines_prefix.clone();
21413                    current_line_len = subsequent_lines_prefix_len;
21414                } else if have_preceding_whitespace {
21415                    continue;
21416                } else if current_line_len + 1 > wrap_column
21417                    && current_line_len != current_prefix_len
21418                {
21419                    wrapped_text.push_str(current_line.trim_end());
21420                    wrapped_text.push('\n');
21421                    is_first_line = false;
21422                    current_line = subsequent_lines_prefix.clone();
21423                    current_line_len = subsequent_lines_prefix_len;
21424                } else if current_line_len != current_prefix_len {
21425                    current_line.push(' ');
21426                    current_line_len += 1;
21427                }
21428            }
21429        }
21430    }
21431
21432    if !current_line.is_empty() {
21433        wrapped_text.push_str(&current_line);
21434    }
21435    wrapped_text
21436}
21437
21438#[test]
21439fn test_wrap_with_prefix() {
21440    assert_eq!(
21441        wrap_with_prefix(
21442            "# ".to_string(),
21443            "# ".to_string(),
21444            "abcdefg".to_string(),
21445            4,
21446            NonZeroU32::new(4).unwrap(),
21447            false,
21448        ),
21449        "# abcdefg"
21450    );
21451    assert_eq!(
21452        wrap_with_prefix(
21453            "".to_string(),
21454            "".to_string(),
21455            "\thello world".to_string(),
21456            8,
21457            NonZeroU32::new(4).unwrap(),
21458            false,
21459        ),
21460        "hello\nworld"
21461    );
21462    assert_eq!(
21463        wrap_with_prefix(
21464            "// ".to_string(),
21465            "// ".to_string(),
21466            "xx \nyy zz aa bb cc".to_string(),
21467            12,
21468            NonZeroU32::new(4).unwrap(),
21469            false,
21470        ),
21471        "// xx yy zz\n// aa bb cc"
21472    );
21473    assert_eq!(
21474        wrap_with_prefix(
21475            String::new(),
21476            String::new(),
21477            "这是什么 \n 钢笔".to_string(),
21478            3,
21479            NonZeroU32::new(4).unwrap(),
21480            false,
21481        ),
21482        "这是什\n么 钢\n"
21483    );
21484}
21485
21486pub trait CollaborationHub {
21487    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21488    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21489    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21490}
21491
21492impl CollaborationHub for Entity<Project> {
21493    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21494        self.read(cx).collaborators()
21495    }
21496
21497    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21498        self.read(cx).user_store().read(cx).participant_indices()
21499    }
21500
21501    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21502        let this = self.read(cx);
21503        let user_ids = this.collaborators().values().map(|c| c.user_id);
21504        this.user_store().read(cx).participant_names(user_ids, cx)
21505    }
21506}
21507
21508pub trait SemanticsProvider {
21509    fn hover(
21510        &self,
21511        buffer: &Entity<Buffer>,
21512        position: text::Anchor,
21513        cx: &mut App,
21514    ) -> Option<Task<Vec<project::Hover>>>;
21515
21516    fn inline_values(
21517        &self,
21518        buffer_handle: Entity<Buffer>,
21519        range: Range<text::Anchor>,
21520        cx: &mut App,
21521    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21522
21523    fn inlay_hints(
21524        &self,
21525        buffer_handle: Entity<Buffer>,
21526        range: Range<text::Anchor>,
21527        cx: &mut App,
21528    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21529
21530    fn resolve_inlay_hint(
21531        &self,
21532        hint: InlayHint,
21533        buffer_handle: Entity<Buffer>,
21534        server_id: LanguageServerId,
21535        cx: &mut App,
21536    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21537
21538    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21539
21540    fn document_highlights(
21541        &self,
21542        buffer: &Entity<Buffer>,
21543        position: text::Anchor,
21544        cx: &mut App,
21545    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21546
21547    fn definitions(
21548        &self,
21549        buffer: &Entity<Buffer>,
21550        position: text::Anchor,
21551        kind: GotoDefinitionKind,
21552        cx: &mut App,
21553    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21554
21555    fn range_for_rename(
21556        &self,
21557        buffer: &Entity<Buffer>,
21558        position: text::Anchor,
21559        cx: &mut App,
21560    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21561
21562    fn perform_rename(
21563        &self,
21564        buffer: &Entity<Buffer>,
21565        position: text::Anchor,
21566        new_name: String,
21567        cx: &mut App,
21568    ) -> Option<Task<Result<ProjectTransaction>>>;
21569}
21570
21571pub trait CompletionProvider {
21572    fn completions(
21573        &self,
21574        excerpt_id: ExcerptId,
21575        buffer: &Entity<Buffer>,
21576        buffer_position: text::Anchor,
21577        trigger: CompletionContext,
21578        window: &mut Window,
21579        cx: &mut Context<Editor>,
21580    ) -> Task<Result<Vec<CompletionResponse>>>;
21581
21582    fn resolve_completions(
21583        &self,
21584        _buffer: Entity<Buffer>,
21585        _completion_indices: Vec<usize>,
21586        _completions: Rc<RefCell<Box<[Completion]>>>,
21587        _cx: &mut Context<Editor>,
21588    ) -> Task<Result<bool>> {
21589        Task::ready(Ok(false))
21590    }
21591
21592    fn apply_additional_edits_for_completion(
21593        &self,
21594        _buffer: Entity<Buffer>,
21595        _completions: Rc<RefCell<Box<[Completion]>>>,
21596        _completion_index: usize,
21597        _push_to_history: bool,
21598        _cx: &mut Context<Editor>,
21599    ) -> Task<Result<Option<language::Transaction>>> {
21600        Task::ready(Ok(None))
21601    }
21602
21603    fn is_completion_trigger(
21604        &self,
21605        buffer: &Entity<Buffer>,
21606        position: language::Anchor,
21607        text: &str,
21608        trigger_in_words: bool,
21609        menu_is_open: bool,
21610        cx: &mut Context<Editor>,
21611    ) -> bool;
21612
21613    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21614
21615    fn sort_completions(&self) -> bool {
21616        true
21617    }
21618
21619    fn filter_completions(&self) -> bool {
21620        true
21621    }
21622}
21623
21624pub trait CodeActionProvider {
21625    fn id(&self) -> Arc<str>;
21626
21627    fn code_actions(
21628        &self,
21629        buffer: &Entity<Buffer>,
21630        range: Range<text::Anchor>,
21631        window: &mut Window,
21632        cx: &mut App,
21633    ) -> Task<Result<Vec<CodeAction>>>;
21634
21635    fn apply_code_action(
21636        &self,
21637        buffer_handle: Entity<Buffer>,
21638        action: CodeAction,
21639        excerpt_id: ExcerptId,
21640        push_to_history: bool,
21641        window: &mut Window,
21642        cx: &mut App,
21643    ) -> Task<Result<ProjectTransaction>>;
21644}
21645
21646impl CodeActionProvider for Entity<Project> {
21647    fn id(&self) -> Arc<str> {
21648        "project".into()
21649    }
21650
21651    fn code_actions(
21652        &self,
21653        buffer: &Entity<Buffer>,
21654        range: Range<text::Anchor>,
21655        _window: &mut Window,
21656        cx: &mut App,
21657    ) -> Task<Result<Vec<CodeAction>>> {
21658        self.update(cx, |project, cx| {
21659            let code_lens = project.code_lens(buffer, range.clone(), cx);
21660            let code_actions = project.code_actions(buffer, range, None, cx);
21661            cx.background_spawn(async move {
21662                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21663                Ok(code_lens
21664                    .context("code lens fetch")?
21665                    .into_iter()
21666                    .chain(code_actions.context("code action fetch")?)
21667                    .collect())
21668            })
21669        })
21670    }
21671
21672    fn apply_code_action(
21673        &self,
21674        buffer_handle: Entity<Buffer>,
21675        action: CodeAction,
21676        _excerpt_id: ExcerptId,
21677        push_to_history: bool,
21678        _window: &mut Window,
21679        cx: &mut App,
21680    ) -> Task<Result<ProjectTransaction>> {
21681        self.update(cx, |project, cx| {
21682            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21683        })
21684    }
21685}
21686
21687fn snippet_completions(
21688    project: &Project,
21689    buffer: &Entity<Buffer>,
21690    buffer_position: text::Anchor,
21691    cx: &mut App,
21692) -> Task<Result<CompletionResponse>> {
21693    let languages = buffer.read(cx).languages_at(buffer_position);
21694    let snippet_store = project.snippets().read(cx);
21695
21696    let scopes: Vec<_> = languages
21697        .iter()
21698        .filter_map(|language| {
21699            let language_name = language.lsp_id();
21700            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21701
21702            if snippets.is_empty() {
21703                None
21704            } else {
21705                Some((language.default_scope(), snippets))
21706            }
21707        })
21708        .collect();
21709
21710    if scopes.is_empty() {
21711        return Task::ready(Ok(CompletionResponse {
21712            completions: vec![],
21713            is_incomplete: false,
21714        }));
21715    }
21716
21717    let snapshot = buffer.read(cx).text_snapshot();
21718    let chars: String = snapshot
21719        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21720        .collect();
21721    let executor = cx.background_executor().clone();
21722
21723    cx.background_spawn(async move {
21724        let mut is_incomplete = false;
21725        let mut completions: Vec<Completion> = Vec::new();
21726        for (scope, snippets) in scopes.into_iter() {
21727            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21728            let mut last_word = chars
21729                .chars()
21730                .take_while(|c| classifier.is_word(*c))
21731                .collect::<String>();
21732            last_word = last_word.chars().rev().collect();
21733
21734            if last_word.is_empty() {
21735                return Ok(CompletionResponse {
21736                    completions: vec![],
21737                    is_incomplete: true,
21738                });
21739            }
21740
21741            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21742            let to_lsp = |point: &text::Anchor| {
21743                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21744                point_to_lsp(end)
21745            };
21746            let lsp_end = to_lsp(&buffer_position);
21747
21748            let candidates = snippets
21749                .iter()
21750                .enumerate()
21751                .flat_map(|(ix, snippet)| {
21752                    snippet
21753                        .prefix
21754                        .iter()
21755                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21756                })
21757                .collect::<Vec<StringMatchCandidate>>();
21758
21759            const MAX_RESULTS: usize = 100;
21760            let mut matches = fuzzy::match_strings(
21761                &candidates,
21762                &last_word,
21763                last_word.chars().any(|c| c.is_uppercase()),
21764                true,
21765                MAX_RESULTS,
21766                &Default::default(),
21767                executor.clone(),
21768            )
21769            .await;
21770
21771            if matches.len() >= MAX_RESULTS {
21772                is_incomplete = true;
21773            }
21774
21775            // Remove all candidates where the query's start does not match the start of any word in the candidate
21776            if let Some(query_start) = last_word.chars().next() {
21777                matches.retain(|string_match| {
21778                    split_words(&string_match.string).any(|word| {
21779                        // Check that the first codepoint of the word as lowercase matches the first
21780                        // codepoint of the query as lowercase
21781                        word.chars()
21782                            .flat_map(|codepoint| codepoint.to_lowercase())
21783                            .zip(query_start.to_lowercase())
21784                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21785                    })
21786                });
21787            }
21788
21789            let matched_strings = matches
21790                .into_iter()
21791                .map(|m| m.string)
21792                .collect::<HashSet<_>>();
21793
21794            completions.extend(snippets.iter().filter_map(|snippet| {
21795                let matching_prefix = snippet
21796                    .prefix
21797                    .iter()
21798                    .find(|prefix| matched_strings.contains(*prefix))?;
21799                let start = as_offset - last_word.len();
21800                let start = snapshot.anchor_before(start);
21801                let range = start..buffer_position;
21802                let lsp_start = to_lsp(&start);
21803                let lsp_range = lsp::Range {
21804                    start: lsp_start,
21805                    end: lsp_end,
21806                };
21807                Some(Completion {
21808                    replace_range: range,
21809                    new_text: snippet.body.clone(),
21810                    source: CompletionSource::Lsp {
21811                        insert_range: None,
21812                        server_id: LanguageServerId(usize::MAX),
21813                        resolved: true,
21814                        lsp_completion: Box::new(lsp::CompletionItem {
21815                            label: snippet.prefix.first().unwrap().clone(),
21816                            kind: Some(CompletionItemKind::SNIPPET),
21817                            label_details: snippet.description.as_ref().map(|description| {
21818                                lsp::CompletionItemLabelDetails {
21819                                    detail: Some(description.clone()),
21820                                    description: None,
21821                                }
21822                            }),
21823                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21824                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21825                                lsp::InsertReplaceEdit {
21826                                    new_text: snippet.body.clone(),
21827                                    insert: lsp_range,
21828                                    replace: lsp_range,
21829                                },
21830                            )),
21831                            filter_text: Some(snippet.body.clone()),
21832                            sort_text: Some(char::MAX.to_string()),
21833                            ..lsp::CompletionItem::default()
21834                        }),
21835                        lsp_defaults: None,
21836                    },
21837                    label: CodeLabel {
21838                        text: matching_prefix.clone(),
21839                        runs: Vec::new(),
21840                        filter_range: 0..matching_prefix.len(),
21841                    },
21842                    icon_path: None,
21843                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21844                        single_line: snippet.name.clone().into(),
21845                        plain_text: snippet
21846                            .description
21847                            .clone()
21848                            .map(|description| description.into()),
21849                    }),
21850                    insert_text_mode: None,
21851                    confirm: None,
21852                })
21853            }))
21854        }
21855
21856        Ok(CompletionResponse {
21857            completions,
21858            is_incomplete,
21859        })
21860    })
21861}
21862
21863impl CompletionProvider for Entity<Project> {
21864    fn completions(
21865        &self,
21866        _excerpt_id: ExcerptId,
21867        buffer: &Entity<Buffer>,
21868        buffer_position: text::Anchor,
21869        options: CompletionContext,
21870        _window: &mut Window,
21871        cx: &mut Context<Editor>,
21872    ) -> Task<Result<Vec<CompletionResponse>>> {
21873        self.update(cx, |project, cx| {
21874            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21875            let project_completions = project.completions(buffer, buffer_position, options, cx);
21876            cx.background_spawn(async move {
21877                let mut responses = project_completions.await?;
21878                let snippets = snippets.await?;
21879                if !snippets.completions.is_empty() {
21880                    responses.push(snippets);
21881                }
21882                Ok(responses)
21883            })
21884        })
21885    }
21886
21887    fn resolve_completions(
21888        &self,
21889        buffer: Entity<Buffer>,
21890        completion_indices: Vec<usize>,
21891        completions: Rc<RefCell<Box<[Completion]>>>,
21892        cx: &mut Context<Editor>,
21893    ) -> Task<Result<bool>> {
21894        self.update(cx, |project, cx| {
21895            project.lsp_store().update(cx, |lsp_store, cx| {
21896                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21897            })
21898        })
21899    }
21900
21901    fn apply_additional_edits_for_completion(
21902        &self,
21903        buffer: Entity<Buffer>,
21904        completions: Rc<RefCell<Box<[Completion]>>>,
21905        completion_index: usize,
21906        push_to_history: bool,
21907        cx: &mut Context<Editor>,
21908    ) -> Task<Result<Option<language::Transaction>>> {
21909        self.update(cx, |project, cx| {
21910            project.lsp_store().update(cx, |lsp_store, cx| {
21911                lsp_store.apply_additional_edits_for_completion(
21912                    buffer,
21913                    completions,
21914                    completion_index,
21915                    push_to_history,
21916                    cx,
21917                )
21918            })
21919        })
21920    }
21921
21922    fn is_completion_trigger(
21923        &self,
21924        buffer: &Entity<Buffer>,
21925        position: language::Anchor,
21926        text: &str,
21927        trigger_in_words: bool,
21928        menu_is_open: bool,
21929        cx: &mut Context<Editor>,
21930    ) -> bool {
21931        let mut chars = text.chars();
21932        let char = if let Some(char) = chars.next() {
21933            char
21934        } else {
21935            return false;
21936        };
21937        if chars.next().is_some() {
21938            return false;
21939        }
21940
21941        let buffer = buffer.read(cx);
21942        let snapshot = buffer.snapshot();
21943        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21944            return false;
21945        }
21946        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21947        if trigger_in_words && classifier.is_word(char) {
21948            return true;
21949        }
21950
21951        buffer.completion_triggers().contains(text)
21952    }
21953}
21954
21955impl SemanticsProvider for Entity<Project> {
21956    fn hover(
21957        &self,
21958        buffer: &Entity<Buffer>,
21959        position: text::Anchor,
21960        cx: &mut App,
21961    ) -> Option<Task<Vec<project::Hover>>> {
21962        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21963    }
21964
21965    fn document_highlights(
21966        &self,
21967        buffer: &Entity<Buffer>,
21968        position: text::Anchor,
21969        cx: &mut App,
21970    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21971        Some(self.update(cx, |project, cx| {
21972            project.document_highlights(buffer, position, cx)
21973        }))
21974    }
21975
21976    fn definitions(
21977        &self,
21978        buffer: &Entity<Buffer>,
21979        position: text::Anchor,
21980        kind: GotoDefinitionKind,
21981        cx: &mut App,
21982    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21983        Some(self.update(cx, |project, cx| match kind {
21984            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
21985            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
21986            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
21987            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
21988        }))
21989    }
21990
21991    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21992        // TODO: make this work for remote projects
21993        self.update(cx, |project, cx| {
21994            if project
21995                .active_debug_session(cx)
21996                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21997            {
21998                return true;
21999            }
22000
22001            buffer.update(cx, |buffer, cx| {
22002                project.any_language_server_supports_inlay_hints(buffer, cx)
22003            })
22004        })
22005    }
22006
22007    fn inline_values(
22008        &self,
22009        buffer_handle: Entity<Buffer>,
22010        range: Range<text::Anchor>,
22011        cx: &mut App,
22012    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22013        self.update(cx, |project, cx| {
22014            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22015
22016            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22017        })
22018    }
22019
22020    fn inlay_hints(
22021        &self,
22022        buffer_handle: Entity<Buffer>,
22023        range: Range<text::Anchor>,
22024        cx: &mut App,
22025    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22026        Some(self.update(cx, |project, cx| {
22027            project.inlay_hints(buffer_handle, range, cx)
22028        }))
22029    }
22030
22031    fn resolve_inlay_hint(
22032        &self,
22033        hint: InlayHint,
22034        buffer_handle: Entity<Buffer>,
22035        server_id: LanguageServerId,
22036        cx: &mut App,
22037    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22038        Some(self.update(cx, |project, cx| {
22039            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22040        }))
22041    }
22042
22043    fn range_for_rename(
22044        &self,
22045        buffer: &Entity<Buffer>,
22046        position: text::Anchor,
22047        cx: &mut App,
22048    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22049        Some(self.update(cx, |project, cx| {
22050            let buffer = buffer.clone();
22051            let task = project.prepare_rename(buffer.clone(), position, cx);
22052            cx.spawn(async move |_, cx| {
22053                Ok(match task.await? {
22054                    PrepareRenameResponse::Success(range) => Some(range),
22055                    PrepareRenameResponse::InvalidPosition => None,
22056                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22057                        // Fallback on using TreeSitter info to determine identifier range
22058                        buffer.read_with(cx, |buffer, _| {
22059                            let snapshot = buffer.snapshot();
22060                            let (range, kind) = snapshot.surrounding_word(position);
22061                            if kind != Some(CharKind::Word) {
22062                                return None;
22063                            }
22064                            Some(
22065                                snapshot.anchor_before(range.start)
22066                                    ..snapshot.anchor_after(range.end),
22067                            )
22068                        })?
22069                    }
22070                })
22071            })
22072        }))
22073    }
22074
22075    fn perform_rename(
22076        &self,
22077        buffer: &Entity<Buffer>,
22078        position: text::Anchor,
22079        new_name: String,
22080        cx: &mut App,
22081    ) -> Option<Task<Result<ProjectTransaction>>> {
22082        Some(self.update(cx, |project, cx| {
22083            project.perform_rename(buffer.clone(), position, new_name, cx)
22084        }))
22085    }
22086}
22087
22088fn inlay_hint_settings(
22089    location: Anchor,
22090    snapshot: &MultiBufferSnapshot,
22091    cx: &mut Context<Editor>,
22092) -> InlayHintSettings {
22093    let file = snapshot.file_at(location);
22094    let language = snapshot.language_at(location).map(|l| l.name());
22095    language_settings(language, file, cx).inlay_hints
22096}
22097
22098fn consume_contiguous_rows(
22099    contiguous_row_selections: &mut Vec<Selection<Point>>,
22100    selection: &Selection<Point>,
22101    display_map: &DisplaySnapshot,
22102    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22103) -> (MultiBufferRow, MultiBufferRow) {
22104    contiguous_row_selections.push(selection.clone());
22105    let start_row = MultiBufferRow(selection.start.row);
22106    let mut end_row = ending_row(selection, display_map);
22107
22108    while let Some(next_selection) = selections.peek() {
22109        if next_selection.start.row <= end_row.0 {
22110            end_row = ending_row(next_selection, display_map);
22111            contiguous_row_selections.push(selections.next().unwrap().clone());
22112        } else {
22113            break;
22114        }
22115    }
22116    (start_row, end_row)
22117}
22118
22119fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22120    if next_selection.end.column > 0 || next_selection.is_empty() {
22121        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22122    } else {
22123        MultiBufferRow(next_selection.end.row)
22124    }
22125}
22126
22127impl EditorSnapshot {
22128    pub fn remote_selections_in_range<'a>(
22129        &'a self,
22130        range: &'a Range<Anchor>,
22131        collaboration_hub: &dyn CollaborationHub,
22132        cx: &'a App,
22133    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22134        let participant_names = collaboration_hub.user_names(cx);
22135        let participant_indices = collaboration_hub.user_participant_indices(cx);
22136        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22137        let collaborators_by_replica_id = collaborators_by_peer_id
22138            .values()
22139            .map(|collaborator| (collaborator.replica_id, collaborator))
22140            .collect::<HashMap<_, _>>();
22141        self.buffer_snapshot
22142            .selections_in_range(range, false)
22143            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22144                if replica_id == AGENT_REPLICA_ID {
22145                    Some(RemoteSelection {
22146                        replica_id,
22147                        selection,
22148                        cursor_shape,
22149                        line_mode,
22150                        collaborator_id: CollaboratorId::Agent,
22151                        user_name: Some("Agent".into()),
22152                        color: cx.theme().players().agent(),
22153                    })
22154                } else {
22155                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22156                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22157                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22158                    Some(RemoteSelection {
22159                        replica_id,
22160                        selection,
22161                        cursor_shape,
22162                        line_mode,
22163                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22164                        user_name,
22165                        color: if let Some(index) = participant_index {
22166                            cx.theme().players().color_for_participant(index.0)
22167                        } else {
22168                            cx.theme().players().absent()
22169                        },
22170                    })
22171                }
22172            })
22173    }
22174
22175    pub fn hunks_for_ranges(
22176        &self,
22177        ranges: impl IntoIterator<Item = Range<Point>>,
22178    ) -> Vec<MultiBufferDiffHunk> {
22179        let mut hunks = Vec::new();
22180        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22181            HashMap::default();
22182        for query_range in ranges {
22183            let query_rows =
22184                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22185            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22186                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22187            ) {
22188                // Include deleted hunks that are adjacent to the query range, because
22189                // otherwise they would be missed.
22190                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22191                if hunk.status().is_deleted() {
22192                    intersects_range |= hunk.row_range.start == query_rows.end;
22193                    intersects_range |= hunk.row_range.end == query_rows.start;
22194                }
22195                if intersects_range {
22196                    if !processed_buffer_rows
22197                        .entry(hunk.buffer_id)
22198                        .or_default()
22199                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22200                    {
22201                        continue;
22202                    }
22203                    hunks.push(hunk);
22204                }
22205            }
22206        }
22207
22208        hunks
22209    }
22210
22211    fn display_diff_hunks_for_rows<'a>(
22212        &'a self,
22213        display_rows: Range<DisplayRow>,
22214        folded_buffers: &'a HashSet<BufferId>,
22215    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22216        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22217        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22218
22219        self.buffer_snapshot
22220            .diff_hunks_in_range(buffer_start..buffer_end)
22221            .filter_map(|hunk| {
22222                if folded_buffers.contains(&hunk.buffer_id) {
22223                    return None;
22224                }
22225
22226                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22227                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22228
22229                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22230                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22231
22232                let display_hunk = if hunk_display_start.column() != 0 {
22233                    DisplayDiffHunk::Folded {
22234                        display_row: hunk_display_start.row(),
22235                    }
22236                } else {
22237                    let mut end_row = hunk_display_end.row();
22238                    if hunk_display_end.column() > 0 {
22239                        end_row.0 += 1;
22240                    }
22241                    let is_created_file = hunk.is_created_file();
22242                    DisplayDiffHunk::Unfolded {
22243                        status: hunk.status(),
22244                        diff_base_byte_range: hunk.diff_base_byte_range,
22245                        display_row_range: hunk_display_start.row()..end_row,
22246                        multi_buffer_range: Anchor::range_in_buffer(
22247                            hunk.excerpt_id,
22248                            hunk.buffer_id,
22249                            hunk.buffer_range,
22250                        ),
22251                        is_created_file,
22252                    }
22253                };
22254
22255                Some(display_hunk)
22256            })
22257    }
22258
22259    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22260        self.display_snapshot.buffer_snapshot.language_at(position)
22261    }
22262
22263    pub fn is_focused(&self) -> bool {
22264        self.is_focused
22265    }
22266
22267    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22268        self.placeholder_text.as_ref()
22269    }
22270
22271    pub fn scroll_position(&self) -> gpui::Point<f32> {
22272        self.scroll_anchor.scroll_position(&self.display_snapshot)
22273    }
22274
22275    fn gutter_dimensions(
22276        &self,
22277        font_id: FontId,
22278        font_size: Pixels,
22279        max_line_number_width: Pixels,
22280        cx: &App,
22281    ) -> Option<GutterDimensions> {
22282        if !self.show_gutter {
22283            return None;
22284        }
22285
22286        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22287        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22288
22289        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22290            matches!(
22291                ProjectSettings::get_global(cx).git.git_gutter,
22292                Some(GitGutterSetting::TrackedFiles)
22293            )
22294        });
22295        let gutter_settings = EditorSettings::get_global(cx).gutter;
22296        let show_line_numbers = self
22297            .show_line_numbers
22298            .unwrap_or(gutter_settings.line_numbers);
22299        let line_gutter_width = if show_line_numbers {
22300            // Avoid flicker-like gutter resizes when the line number gains another digit by
22301            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22302            let min_width_for_number_on_gutter =
22303                ch_advance * gutter_settings.min_line_number_digits as f32;
22304            max_line_number_width.max(min_width_for_number_on_gutter)
22305        } else {
22306            0.0.into()
22307        };
22308
22309        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22310        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22311
22312        let git_blame_entries_width =
22313            self.git_blame_gutter_max_author_length
22314                .map(|max_author_length| {
22315                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22316                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22317
22318                    /// The number of characters to dedicate to gaps and margins.
22319                    const SPACING_WIDTH: usize = 4;
22320
22321                    let max_char_count = max_author_length.min(renderer.max_author_length())
22322                        + ::git::SHORT_SHA_LENGTH
22323                        + MAX_RELATIVE_TIMESTAMP.len()
22324                        + SPACING_WIDTH;
22325
22326                    ch_advance * max_char_count
22327                });
22328
22329        let is_singleton = self.buffer_snapshot.is_singleton();
22330
22331        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22332        left_padding += if !is_singleton {
22333            ch_width * 4.0
22334        } else if show_runnables || show_breakpoints {
22335            ch_width * 3.0
22336        } else if show_git_gutter && show_line_numbers {
22337            ch_width * 2.0
22338        } else if show_git_gutter || show_line_numbers {
22339            ch_width
22340        } else {
22341            px(0.)
22342        };
22343
22344        let shows_folds = is_singleton && gutter_settings.folds;
22345
22346        let right_padding = if shows_folds && show_line_numbers {
22347            ch_width * 4.0
22348        } else if shows_folds || (!is_singleton && show_line_numbers) {
22349            ch_width * 3.0
22350        } else if show_line_numbers {
22351            ch_width
22352        } else {
22353            px(0.)
22354        };
22355
22356        Some(GutterDimensions {
22357            left_padding,
22358            right_padding,
22359            width: line_gutter_width + left_padding + right_padding,
22360            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22361            git_blame_entries_width,
22362        })
22363    }
22364
22365    pub fn render_crease_toggle(
22366        &self,
22367        buffer_row: MultiBufferRow,
22368        row_contains_cursor: bool,
22369        editor: Entity<Editor>,
22370        window: &mut Window,
22371        cx: &mut App,
22372    ) -> Option<AnyElement> {
22373        let folded = self.is_line_folded(buffer_row);
22374        let mut is_foldable = false;
22375
22376        if let Some(crease) = self
22377            .crease_snapshot
22378            .query_row(buffer_row, &self.buffer_snapshot)
22379        {
22380            is_foldable = true;
22381            match crease {
22382                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22383                    if let Some(render_toggle) = render_toggle {
22384                        let toggle_callback =
22385                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22386                                if folded {
22387                                    editor.update(cx, |editor, cx| {
22388                                        editor.fold_at(buffer_row, window, cx)
22389                                    });
22390                                } else {
22391                                    editor.update(cx, |editor, cx| {
22392                                        editor.unfold_at(buffer_row, window, cx)
22393                                    });
22394                                }
22395                            });
22396                        return Some((render_toggle)(
22397                            buffer_row,
22398                            folded,
22399                            toggle_callback,
22400                            window,
22401                            cx,
22402                        ));
22403                    }
22404                }
22405            }
22406        }
22407
22408        is_foldable |= self.starts_indent(buffer_row);
22409
22410        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22411            Some(
22412                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22413                    .toggle_state(folded)
22414                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22415                        if folded {
22416                            this.unfold_at(buffer_row, window, cx);
22417                        } else {
22418                            this.fold_at(buffer_row, window, cx);
22419                        }
22420                    }))
22421                    .into_any_element(),
22422            )
22423        } else {
22424            None
22425        }
22426    }
22427
22428    pub fn render_crease_trailer(
22429        &self,
22430        buffer_row: MultiBufferRow,
22431        window: &mut Window,
22432        cx: &mut App,
22433    ) -> Option<AnyElement> {
22434        let folded = self.is_line_folded(buffer_row);
22435        if let Crease::Inline { render_trailer, .. } = self
22436            .crease_snapshot
22437            .query_row(buffer_row, &self.buffer_snapshot)?
22438        {
22439            let render_trailer = render_trailer.as_ref()?;
22440            Some(render_trailer(buffer_row, folded, window, cx))
22441        } else {
22442            None
22443        }
22444    }
22445}
22446
22447impl Deref for EditorSnapshot {
22448    type Target = DisplaySnapshot;
22449
22450    fn deref(&self) -> &Self::Target {
22451        &self.display_snapshot
22452    }
22453}
22454
22455#[derive(Clone, Debug, PartialEq, Eq)]
22456pub enum EditorEvent {
22457    InputIgnored {
22458        text: Arc<str>,
22459    },
22460    InputHandled {
22461        utf16_range_to_replace: Option<Range<isize>>,
22462        text: Arc<str>,
22463    },
22464    ExcerptsAdded {
22465        buffer: Entity<Buffer>,
22466        predecessor: ExcerptId,
22467        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22468    },
22469    ExcerptsRemoved {
22470        ids: Vec<ExcerptId>,
22471        removed_buffer_ids: Vec<BufferId>,
22472    },
22473    BufferFoldToggled {
22474        ids: Vec<ExcerptId>,
22475        folded: bool,
22476    },
22477    ExcerptsEdited {
22478        ids: Vec<ExcerptId>,
22479    },
22480    ExcerptsExpanded {
22481        ids: Vec<ExcerptId>,
22482    },
22483    BufferEdited,
22484    Edited {
22485        transaction_id: clock::Lamport,
22486    },
22487    Reparsed(BufferId),
22488    Focused,
22489    FocusedIn,
22490    Blurred,
22491    DirtyChanged,
22492    Saved,
22493    TitleChanged,
22494    DiffBaseChanged,
22495    SelectionsChanged {
22496        local: bool,
22497    },
22498    ScrollPositionChanged {
22499        local: bool,
22500        autoscroll: bool,
22501    },
22502    Closed,
22503    TransactionUndone {
22504        transaction_id: clock::Lamport,
22505    },
22506    TransactionBegun {
22507        transaction_id: clock::Lamport,
22508    },
22509    Reloaded,
22510    CursorShapeChanged,
22511    PushedToNavHistory {
22512        anchor: Anchor,
22513        is_deactivate: bool,
22514    },
22515}
22516
22517impl EventEmitter<EditorEvent> for Editor {}
22518
22519impl Focusable for Editor {
22520    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22521        self.focus_handle.clone()
22522    }
22523}
22524
22525impl Render for Editor {
22526    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22527        let settings = ThemeSettings::get_global(cx);
22528
22529        let mut text_style = match self.mode {
22530            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22531                color: cx.theme().colors().editor_foreground,
22532                font_family: settings.ui_font.family.clone(),
22533                font_features: settings.ui_font.features.clone(),
22534                font_fallbacks: settings.ui_font.fallbacks.clone(),
22535                font_size: rems(0.875).into(),
22536                font_weight: settings.ui_font.weight,
22537                line_height: relative(settings.buffer_line_height.value()),
22538                ..Default::default()
22539            },
22540            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22541                color: cx.theme().colors().editor_foreground,
22542                font_family: settings.buffer_font.family.clone(),
22543                font_features: settings.buffer_font.features.clone(),
22544                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22545                font_size: settings.buffer_font_size(cx).into(),
22546                font_weight: settings.buffer_font.weight,
22547                line_height: relative(settings.buffer_line_height.value()),
22548                ..Default::default()
22549            },
22550        };
22551        if let Some(text_style_refinement) = &self.text_style_refinement {
22552            text_style.refine(text_style_refinement)
22553        }
22554
22555        let background = match self.mode {
22556            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22557            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22558            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22559            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22560        };
22561
22562        EditorElement::new(
22563            &cx.entity(),
22564            EditorStyle {
22565                background,
22566                border: cx.theme().colors().border,
22567                local_player: cx.theme().players().local(),
22568                text: text_style,
22569                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22570                syntax: cx.theme().syntax().clone(),
22571                status: cx.theme().status().clone(),
22572                inlay_hints_style: make_inlay_hints_style(cx),
22573                inline_completion_styles: make_suggestion_styles(cx),
22574                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22575                show_underlines: self.diagnostics_enabled(),
22576            },
22577        )
22578    }
22579}
22580
22581impl EntityInputHandler for Editor {
22582    fn text_for_range(
22583        &mut self,
22584        range_utf16: Range<usize>,
22585        adjusted_range: &mut Option<Range<usize>>,
22586        _: &mut Window,
22587        cx: &mut Context<Self>,
22588    ) -> Option<String> {
22589        let snapshot = self.buffer.read(cx).read(cx);
22590        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22591        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22592        if (start.0..end.0) != range_utf16 {
22593            adjusted_range.replace(start.0..end.0);
22594        }
22595        Some(snapshot.text_for_range(start..end).collect())
22596    }
22597
22598    fn selected_text_range(
22599        &mut self,
22600        ignore_disabled_input: bool,
22601        _: &mut Window,
22602        cx: &mut Context<Self>,
22603    ) -> Option<UTF16Selection> {
22604        // Prevent the IME menu from appearing when holding down an alphabetic key
22605        // while input is disabled.
22606        if !ignore_disabled_input && !self.input_enabled {
22607            return None;
22608        }
22609
22610        let selection = self.selections.newest::<OffsetUtf16>(cx);
22611        let range = selection.range();
22612
22613        Some(UTF16Selection {
22614            range: range.start.0..range.end.0,
22615            reversed: selection.reversed,
22616        })
22617    }
22618
22619    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22620        let snapshot = self.buffer.read(cx).read(cx);
22621        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22622        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22623    }
22624
22625    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22626        self.clear_highlights::<InputComposition>(cx);
22627        self.ime_transaction.take();
22628    }
22629
22630    fn replace_text_in_range(
22631        &mut self,
22632        range_utf16: Option<Range<usize>>,
22633        text: &str,
22634        window: &mut Window,
22635        cx: &mut Context<Self>,
22636    ) {
22637        if !self.input_enabled {
22638            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22639            return;
22640        }
22641
22642        self.transact(window, cx, |this, window, cx| {
22643            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22644                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22645                Some(this.selection_replacement_ranges(range_utf16, cx))
22646            } else {
22647                this.marked_text_ranges(cx)
22648            };
22649
22650            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22651                let newest_selection_id = this.selections.newest_anchor().id;
22652                this.selections
22653                    .all::<OffsetUtf16>(cx)
22654                    .iter()
22655                    .zip(ranges_to_replace.iter())
22656                    .find_map(|(selection, range)| {
22657                        if selection.id == newest_selection_id {
22658                            Some(
22659                                (range.start.0 as isize - selection.head().0 as isize)
22660                                    ..(range.end.0 as isize - selection.head().0 as isize),
22661                            )
22662                        } else {
22663                            None
22664                        }
22665                    })
22666            });
22667
22668            cx.emit(EditorEvent::InputHandled {
22669                utf16_range_to_replace: range_to_replace,
22670                text: text.into(),
22671            });
22672
22673            if let Some(new_selected_ranges) = new_selected_ranges {
22674                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22675                    selections.select_ranges(new_selected_ranges)
22676                });
22677                this.backspace(&Default::default(), window, cx);
22678            }
22679
22680            this.handle_input(text, window, cx);
22681        });
22682
22683        if let Some(transaction) = self.ime_transaction {
22684            self.buffer.update(cx, |buffer, cx| {
22685                buffer.group_until_transaction(transaction, cx);
22686            });
22687        }
22688
22689        self.unmark_text(window, cx);
22690    }
22691
22692    fn replace_and_mark_text_in_range(
22693        &mut self,
22694        range_utf16: Option<Range<usize>>,
22695        text: &str,
22696        new_selected_range_utf16: Option<Range<usize>>,
22697        window: &mut Window,
22698        cx: &mut Context<Self>,
22699    ) {
22700        if !self.input_enabled {
22701            return;
22702        }
22703
22704        let transaction = self.transact(window, cx, |this, window, cx| {
22705            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22706                let snapshot = this.buffer.read(cx).read(cx);
22707                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22708                    for marked_range in &mut marked_ranges {
22709                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22710                        marked_range.start.0 += relative_range_utf16.start;
22711                        marked_range.start =
22712                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22713                        marked_range.end =
22714                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22715                    }
22716                }
22717                Some(marked_ranges)
22718            } else if let Some(range_utf16) = range_utf16 {
22719                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22720                Some(this.selection_replacement_ranges(range_utf16, cx))
22721            } else {
22722                None
22723            };
22724
22725            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22726                let newest_selection_id = this.selections.newest_anchor().id;
22727                this.selections
22728                    .all::<OffsetUtf16>(cx)
22729                    .iter()
22730                    .zip(ranges_to_replace.iter())
22731                    .find_map(|(selection, range)| {
22732                        if selection.id == newest_selection_id {
22733                            Some(
22734                                (range.start.0 as isize - selection.head().0 as isize)
22735                                    ..(range.end.0 as isize - selection.head().0 as isize),
22736                            )
22737                        } else {
22738                            None
22739                        }
22740                    })
22741            });
22742
22743            cx.emit(EditorEvent::InputHandled {
22744                utf16_range_to_replace: range_to_replace,
22745                text: text.into(),
22746            });
22747
22748            if let Some(ranges) = ranges_to_replace {
22749                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22750                    s.select_ranges(ranges)
22751                });
22752            }
22753
22754            let marked_ranges = {
22755                let snapshot = this.buffer.read(cx).read(cx);
22756                this.selections
22757                    .disjoint_anchors()
22758                    .iter()
22759                    .map(|selection| {
22760                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22761                    })
22762                    .collect::<Vec<_>>()
22763            };
22764
22765            if text.is_empty() {
22766                this.unmark_text(window, cx);
22767            } else {
22768                this.highlight_text::<InputComposition>(
22769                    marked_ranges.clone(),
22770                    HighlightStyle {
22771                        underline: Some(UnderlineStyle {
22772                            thickness: px(1.),
22773                            color: None,
22774                            wavy: false,
22775                        }),
22776                        ..Default::default()
22777                    },
22778                    cx,
22779                );
22780            }
22781
22782            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22783            let use_autoclose = this.use_autoclose;
22784            let use_auto_surround = this.use_auto_surround;
22785            this.set_use_autoclose(false);
22786            this.set_use_auto_surround(false);
22787            this.handle_input(text, window, cx);
22788            this.set_use_autoclose(use_autoclose);
22789            this.set_use_auto_surround(use_auto_surround);
22790
22791            if let Some(new_selected_range) = new_selected_range_utf16 {
22792                let snapshot = this.buffer.read(cx).read(cx);
22793                let new_selected_ranges = marked_ranges
22794                    .into_iter()
22795                    .map(|marked_range| {
22796                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22797                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22798                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22799                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22800                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22801                    })
22802                    .collect::<Vec<_>>();
22803
22804                drop(snapshot);
22805                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22806                    selections.select_ranges(new_selected_ranges)
22807                });
22808            }
22809        });
22810
22811        self.ime_transaction = self.ime_transaction.or(transaction);
22812        if let Some(transaction) = self.ime_transaction {
22813            self.buffer.update(cx, |buffer, cx| {
22814                buffer.group_until_transaction(transaction, cx);
22815            });
22816        }
22817
22818        if self.text_highlights::<InputComposition>(cx).is_none() {
22819            self.ime_transaction.take();
22820        }
22821    }
22822
22823    fn bounds_for_range(
22824        &mut self,
22825        range_utf16: Range<usize>,
22826        element_bounds: gpui::Bounds<Pixels>,
22827        window: &mut Window,
22828        cx: &mut Context<Self>,
22829    ) -> Option<gpui::Bounds<Pixels>> {
22830        let text_layout_details = self.text_layout_details(window);
22831        let CharacterDimensions {
22832            em_width,
22833            em_advance,
22834            line_height,
22835        } = self.character_dimensions(window);
22836
22837        let snapshot = self.snapshot(window, cx);
22838        let scroll_position = snapshot.scroll_position();
22839        let scroll_left = scroll_position.x * em_advance;
22840
22841        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22842        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22843            + self.gutter_dimensions.full_width();
22844        let y = line_height * (start.row().as_f32() - scroll_position.y);
22845
22846        Some(Bounds {
22847            origin: element_bounds.origin + point(x, y),
22848            size: size(em_width, line_height),
22849        })
22850    }
22851
22852    fn character_index_for_point(
22853        &mut self,
22854        point: gpui::Point<Pixels>,
22855        _window: &mut Window,
22856        _cx: &mut Context<Self>,
22857    ) -> Option<usize> {
22858        let position_map = self.last_position_map.as_ref()?;
22859        if !position_map.text_hitbox.contains(&point) {
22860            return None;
22861        }
22862        let display_point = position_map.point_for_position(point).previous_valid;
22863        let anchor = position_map
22864            .snapshot
22865            .display_point_to_anchor(display_point, Bias::Left);
22866        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22867        Some(utf16_offset.0)
22868    }
22869}
22870
22871trait SelectionExt {
22872    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22873    fn spanned_rows(
22874        &self,
22875        include_end_if_at_line_start: bool,
22876        map: &DisplaySnapshot,
22877    ) -> Range<MultiBufferRow>;
22878}
22879
22880impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22881    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22882        let start = self
22883            .start
22884            .to_point(&map.buffer_snapshot)
22885            .to_display_point(map);
22886        let end = self
22887            .end
22888            .to_point(&map.buffer_snapshot)
22889            .to_display_point(map);
22890        if self.reversed {
22891            end..start
22892        } else {
22893            start..end
22894        }
22895    }
22896
22897    fn spanned_rows(
22898        &self,
22899        include_end_if_at_line_start: bool,
22900        map: &DisplaySnapshot,
22901    ) -> Range<MultiBufferRow> {
22902        let start = self.start.to_point(&map.buffer_snapshot);
22903        let mut end = self.end.to_point(&map.buffer_snapshot);
22904        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22905            end.row -= 1;
22906        }
22907
22908        let buffer_start = map.prev_line_boundary(start).0;
22909        let buffer_end = map.next_line_boundary(end).0;
22910        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22911    }
22912}
22913
22914impl<T: InvalidationRegion> InvalidationStack<T> {
22915    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22916    where
22917        S: Clone + ToOffset,
22918    {
22919        while let Some(region) = self.last() {
22920            let all_selections_inside_invalidation_ranges =
22921                if selections.len() == region.ranges().len() {
22922                    selections
22923                        .iter()
22924                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22925                        .all(|(selection, invalidation_range)| {
22926                            let head = selection.head().to_offset(buffer);
22927                            invalidation_range.start <= head && invalidation_range.end >= head
22928                        })
22929                } else {
22930                    false
22931                };
22932
22933            if all_selections_inside_invalidation_ranges {
22934                break;
22935            } else {
22936                self.pop();
22937            }
22938        }
22939    }
22940}
22941
22942impl<T> Default for InvalidationStack<T> {
22943    fn default() -> Self {
22944        Self(Default::default())
22945    }
22946}
22947
22948impl<T> Deref for InvalidationStack<T> {
22949    type Target = Vec<T>;
22950
22951    fn deref(&self) -> &Self::Target {
22952        &self.0
22953    }
22954}
22955
22956impl<T> DerefMut for InvalidationStack<T> {
22957    fn deref_mut(&mut self) -> &mut Self::Target {
22958        &mut self.0
22959    }
22960}
22961
22962impl InvalidationRegion for SnippetState {
22963    fn ranges(&self) -> &[Range<Anchor>] {
22964        &self.ranges[self.active_index]
22965    }
22966}
22967
22968fn inline_completion_edit_text(
22969    current_snapshot: &BufferSnapshot,
22970    edits: &[(Range<Anchor>, String)],
22971    edit_preview: &EditPreview,
22972    include_deletions: bool,
22973    cx: &App,
22974) -> HighlightedText {
22975    let edits = edits
22976        .iter()
22977        .map(|(anchor, text)| {
22978            (
22979                anchor.start.text_anchor..anchor.end.text_anchor,
22980                text.clone(),
22981            )
22982        })
22983        .collect::<Vec<_>>();
22984
22985    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22986}
22987
22988pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22989    match severity {
22990        lsp::DiagnosticSeverity::ERROR => colors.error,
22991        lsp::DiagnosticSeverity::WARNING => colors.warning,
22992        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22993        lsp::DiagnosticSeverity::HINT => colors.info,
22994        _ => colors.ignored,
22995    }
22996}
22997
22998pub fn styled_runs_for_code_label<'a>(
22999    label: &'a CodeLabel,
23000    syntax_theme: &'a theme::SyntaxTheme,
23001) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23002    let fade_out = HighlightStyle {
23003        fade_out: Some(0.35),
23004        ..Default::default()
23005    };
23006
23007    let mut prev_end = label.filter_range.end;
23008    label
23009        .runs
23010        .iter()
23011        .enumerate()
23012        .flat_map(move |(ix, (range, highlight_id))| {
23013            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23014                style
23015            } else {
23016                return Default::default();
23017            };
23018            let mut muted_style = style;
23019            muted_style.highlight(fade_out);
23020
23021            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23022            if range.start >= label.filter_range.end {
23023                if range.start > prev_end {
23024                    runs.push((prev_end..range.start, fade_out));
23025                }
23026                runs.push((range.clone(), muted_style));
23027            } else if range.end <= label.filter_range.end {
23028                runs.push((range.clone(), style));
23029            } else {
23030                runs.push((range.start..label.filter_range.end, style));
23031                runs.push((label.filter_range.end..range.end, muted_style));
23032            }
23033            prev_end = cmp::max(prev_end, range.end);
23034
23035            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23036                runs.push((prev_end..label.text.len(), fade_out));
23037            }
23038
23039            runs
23040        })
23041}
23042
23043pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23044    let mut prev_index = 0;
23045    let mut prev_codepoint: Option<char> = None;
23046    text.char_indices()
23047        .chain([(text.len(), '\0')])
23048        .filter_map(move |(index, codepoint)| {
23049            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23050            let is_boundary = index == text.len()
23051                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23052                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23053            if is_boundary {
23054                let chunk = &text[prev_index..index];
23055                prev_index = index;
23056                Some(chunk)
23057            } else {
23058                None
23059            }
23060        })
23061}
23062
23063pub trait RangeToAnchorExt: Sized {
23064    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23065
23066    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23067        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23068        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23069    }
23070}
23071
23072impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23073    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23074        let start_offset = self.start.to_offset(snapshot);
23075        let end_offset = self.end.to_offset(snapshot);
23076        if start_offset == end_offset {
23077            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23078        } else {
23079            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23080        }
23081    }
23082}
23083
23084pub trait RowExt {
23085    fn as_f32(&self) -> f32;
23086
23087    fn next_row(&self) -> Self;
23088
23089    fn previous_row(&self) -> Self;
23090
23091    fn minus(&self, other: Self) -> u32;
23092}
23093
23094impl RowExt for DisplayRow {
23095    fn as_f32(&self) -> f32 {
23096        self.0 as f32
23097    }
23098
23099    fn next_row(&self) -> Self {
23100        Self(self.0 + 1)
23101    }
23102
23103    fn previous_row(&self) -> Self {
23104        Self(self.0.saturating_sub(1))
23105    }
23106
23107    fn minus(&self, other: Self) -> u32 {
23108        self.0 - other.0
23109    }
23110}
23111
23112impl RowExt for MultiBufferRow {
23113    fn as_f32(&self) -> f32 {
23114        self.0 as f32
23115    }
23116
23117    fn next_row(&self) -> Self {
23118        Self(self.0 + 1)
23119    }
23120
23121    fn previous_row(&self) -> Self {
23122        Self(self.0.saturating_sub(1))
23123    }
23124
23125    fn minus(&self, other: Self) -> u32 {
23126        self.0 - other.0
23127    }
23128}
23129
23130trait RowRangeExt {
23131    type Row;
23132
23133    fn len(&self) -> usize;
23134
23135    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23136}
23137
23138impl RowRangeExt for Range<MultiBufferRow> {
23139    type Row = MultiBufferRow;
23140
23141    fn len(&self) -> usize {
23142        (self.end.0 - self.start.0) as usize
23143    }
23144
23145    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23146        (self.start.0..self.end.0).map(MultiBufferRow)
23147    }
23148}
23149
23150impl RowRangeExt for Range<DisplayRow> {
23151    type Row = DisplayRow;
23152
23153    fn len(&self) -> usize {
23154        (self.end.0 - self.start.0) as usize
23155    }
23156
23157    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23158        (self.start.0..self.end.0).map(DisplayRow)
23159    }
23160}
23161
23162/// If select range has more than one line, we
23163/// just point the cursor to range.start.
23164fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23165    if range.start.row == range.end.row {
23166        range
23167    } else {
23168        range.start..range.start
23169    }
23170}
23171pub struct KillRing(ClipboardItem);
23172impl Global for KillRing {}
23173
23174const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23175
23176enum BreakpointPromptEditAction {
23177    Log,
23178    Condition,
23179    HitCondition,
23180}
23181
23182struct BreakpointPromptEditor {
23183    pub(crate) prompt: Entity<Editor>,
23184    editor: WeakEntity<Editor>,
23185    breakpoint_anchor: Anchor,
23186    breakpoint: Breakpoint,
23187    edit_action: BreakpointPromptEditAction,
23188    block_ids: HashSet<CustomBlockId>,
23189    editor_margins: Arc<Mutex<EditorMargins>>,
23190    _subscriptions: Vec<Subscription>,
23191}
23192
23193impl BreakpointPromptEditor {
23194    const MAX_LINES: u8 = 4;
23195
23196    fn new(
23197        editor: WeakEntity<Editor>,
23198        breakpoint_anchor: Anchor,
23199        breakpoint: Breakpoint,
23200        edit_action: BreakpointPromptEditAction,
23201        window: &mut Window,
23202        cx: &mut Context<Self>,
23203    ) -> Self {
23204        let base_text = match edit_action {
23205            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23206            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23207            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23208        }
23209        .map(|msg| msg.to_string())
23210        .unwrap_or_default();
23211
23212        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23213        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23214
23215        let prompt = cx.new(|cx| {
23216            let mut prompt = Editor::new(
23217                EditorMode::AutoHeight {
23218                    min_lines: 1,
23219                    max_lines: Some(Self::MAX_LINES as usize),
23220                },
23221                buffer,
23222                None,
23223                window,
23224                cx,
23225            );
23226            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23227            prompt.set_show_cursor_when_unfocused(false, cx);
23228            prompt.set_placeholder_text(
23229                match edit_action {
23230                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23231                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23232                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23233                },
23234                cx,
23235            );
23236
23237            prompt
23238        });
23239
23240        Self {
23241            prompt,
23242            editor,
23243            breakpoint_anchor,
23244            breakpoint,
23245            edit_action,
23246            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23247            block_ids: Default::default(),
23248            _subscriptions: vec![],
23249        }
23250    }
23251
23252    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23253        self.block_ids.extend(block_ids)
23254    }
23255
23256    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23257        if let Some(editor) = self.editor.upgrade() {
23258            let message = self
23259                .prompt
23260                .read(cx)
23261                .buffer
23262                .read(cx)
23263                .as_singleton()
23264                .expect("A multi buffer in breakpoint prompt isn't possible")
23265                .read(cx)
23266                .as_rope()
23267                .to_string();
23268
23269            editor.update(cx, |editor, cx| {
23270                editor.edit_breakpoint_at_anchor(
23271                    self.breakpoint_anchor,
23272                    self.breakpoint.clone(),
23273                    match self.edit_action {
23274                        BreakpointPromptEditAction::Log => {
23275                            BreakpointEditAction::EditLogMessage(message.into())
23276                        }
23277                        BreakpointPromptEditAction::Condition => {
23278                            BreakpointEditAction::EditCondition(message.into())
23279                        }
23280                        BreakpointPromptEditAction::HitCondition => {
23281                            BreakpointEditAction::EditHitCondition(message.into())
23282                        }
23283                    },
23284                    cx,
23285                );
23286
23287                editor.remove_blocks(self.block_ids.clone(), None, cx);
23288                cx.focus_self(window);
23289            });
23290        }
23291    }
23292
23293    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23294        self.editor
23295            .update(cx, |editor, cx| {
23296                editor.remove_blocks(self.block_ids.clone(), None, cx);
23297                window.focus(&editor.focus_handle);
23298            })
23299            .log_err();
23300    }
23301
23302    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23303        let settings = ThemeSettings::get_global(cx);
23304        let text_style = TextStyle {
23305            color: if self.prompt.read(cx).read_only(cx) {
23306                cx.theme().colors().text_disabled
23307            } else {
23308                cx.theme().colors().text
23309            },
23310            font_family: settings.buffer_font.family.clone(),
23311            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23312            font_size: settings.buffer_font_size(cx).into(),
23313            font_weight: settings.buffer_font.weight,
23314            line_height: relative(settings.buffer_line_height.value()),
23315            ..Default::default()
23316        };
23317        EditorElement::new(
23318            &self.prompt,
23319            EditorStyle {
23320                background: cx.theme().colors().editor_background,
23321                local_player: cx.theme().players().local(),
23322                text: text_style,
23323                ..Default::default()
23324            },
23325        )
23326    }
23327}
23328
23329impl Render for BreakpointPromptEditor {
23330    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23331        let editor_margins = *self.editor_margins.lock();
23332        let gutter_dimensions = editor_margins.gutter;
23333        h_flex()
23334            .key_context("Editor")
23335            .bg(cx.theme().colors().editor_background)
23336            .border_y_1()
23337            .border_color(cx.theme().status().info_border)
23338            .size_full()
23339            .py(window.line_height() / 2.5)
23340            .on_action(cx.listener(Self::confirm))
23341            .on_action(cx.listener(Self::cancel))
23342            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23343            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23344    }
23345}
23346
23347impl Focusable for BreakpointPromptEditor {
23348    fn focus_handle(&self, cx: &App) -> FocusHandle {
23349        self.prompt.focus_handle(cx)
23350    }
23351}
23352
23353fn all_edits_insertions_or_deletions(
23354    edits: &Vec<(Range<Anchor>, String)>,
23355    snapshot: &MultiBufferSnapshot,
23356) -> bool {
23357    let mut all_insertions = true;
23358    let mut all_deletions = true;
23359
23360    for (range, new_text) in edits.iter() {
23361        let range_is_empty = range.to_offset(&snapshot).is_empty();
23362        let text_is_empty = new_text.is_empty();
23363
23364        if range_is_empty != text_is_empty {
23365            if range_is_empty {
23366                all_deletions = false;
23367            } else {
23368                all_insertions = false;
23369            }
23370        } else {
23371            return false;
23372        }
23373
23374        if !all_insertions && !all_deletions {
23375            return false;
23376        }
23377    }
23378    all_insertions || all_deletions
23379}
23380
23381struct MissingEditPredictionKeybindingTooltip;
23382
23383impl Render for MissingEditPredictionKeybindingTooltip {
23384    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23385        ui::tooltip_container(window, cx, |container, _, cx| {
23386            container
23387                .flex_shrink_0()
23388                .max_w_80()
23389                .min_h(rems_from_px(124.))
23390                .justify_between()
23391                .child(
23392                    v_flex()
23393                        .flex_1()
23394                        .text_ui_sm(cx)
23395                        .child(Label::new("Conflict with Accept Keybinding"))
23396                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23397                )
23398                .child(
23399                    h_flex()
23400                        .pb_1()
23401                        .gap_1()
23402                        .items_end()
23403                        .w_full()
23404                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23405                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23406                        }))
23407                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23408                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23409                        })),
23410                )
23411        })
23412    }
23413}
23414
23415#[derive(Debug, Clone, Copy, PartialEq)]
23416pub struct LineHighlight {
23417    pub background: Background,
23418    pub border: Option<gpui::Hsla>,
23419    pub include_gutter: bool,
23420    pub type_id: Option<TypeId>,
23421}
23422
23423struct LineManipulationResult {
23424    pub new_text: String,
23425    pub line_count_before: usize,
23426    pub line_count_after: usize,
23427}
23428
23429fn render_diff_hunk_controls(
23430    row: u32,
23431    status: &DiffHunkStatus,
23432    hunk_range: Range<Anchor>,
23433    is_created_file: bool,
23434    line_height: Pixels,
23435    editor: &Entity<Editor>,
23436    _window: &mut Window,
23437    cx: &mut App,
23438) -> AnyElement {
23439    h_flex()
23440        .h(line_height)
23441        .mr_1()
23442        .gap_1()
23443        .px_0p5()
23444        .pb_1()
23445        .border_x_1()
23446        .border_b_1()
23447        .border_color(cx.theme().colors().border_variant)
23448        .rounded_b_lg()
23449        .bg(cx.theme().colors().editor_background)
23450        .gap_1()
23451        .block_mouse_except_scroll()
23452        .shadow_md()
23453        .child(if status.has_secondary_hunk() {
23454            Button::new(("stage", row as u64), "Stage")
23455                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23456                .tooltip({
23457                    let focus_handle = editor.focus_handle(cx);
23458                    move |window, cx| {
23459                        Tooltip::for_action_in(
23460                            "Stage Hunk",
23461                            &::git::ToggleStaged,
23462                            &focus_handle,
23463                            window,
23464                            cx,
23465                        )
23466                    }
23467                })
23468                .on_click({
23469                    let editor = editor.clone();
23470                    move |_event, _window, cx| {
23471                        editor.update(cx, |editor, cx| {
23472                            editor.stage_or_unstage_diff_hunks(
23473                                true,
23474                                vec![hunk_range.start..hunk_range.start],
23475                                cx,
23476                            );
23477                        });
23478                    }
23479                })
23480        } else {
23481            Button::new(("unstage", row as u64), "Unstage")
23482                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23483                .tooltip({
23484                    let focus_handle = editor.focus_handle(cx);
23485                    move |window, cx| {
23486                        Tooltip::for_action_in(
23487                            "Unstage Hunk",
23488                            &::git::ToggleStaged,
23489                            &focus_handle,
23490                            window,
23491                            cx,
23492                        )
23493                    }
23494                })
23495                .on_click({
23496                    let editor = editor.clone();
23497                    move |_event, _window, cx| {
23498                        editor.update(cx, |editor, cx| {
23499                            editor.stage_or_unstage_diff_hunks(
23500                                false,
23501                                vec![hunk_range.start..hunk_range.start],
23502                                cx,
23503                            );
23504                        });
23505                    }
23506                })
23507        })
23508        .child(
23509            Button::new(("restore", row as u64), "Restore")
23510                .tooltip({
23511                    let focus_handle = editor.focus_handle(cx);
23512                    move |window, cx| {
23513                        Tooltip::for_action_in(
23514                            "Restore Hunk",
23515                            &::git::Restore,
23516                            &focus_handle,
23517                            window,
23518                            cx,
23519                        )
23520                    }
23521                })
23522                .on_click({
23523                    let editor = editor.clone();
23524                    move |_event, window, cx| {
23525                        editor.update(cx, |editor, cx| {
23526                            let snapshot = editor.snapshot(window, cx);
23527                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23528                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23529                        });
23530                    }
23531                })
23532                .disabled(is_created_file),
23533        )
23534        .when(
23535            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23536            |el| {
23537                el.child(
23538                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23539                        .shape(IconButtonShape::Square)
23540                        .icon_size(IconSize::Small)
23541                        // .disabled(!has_multiple_hunks)
23542                        .tooltip({
23543                            let focus_handle = editor.focus_handle(cx);
23544                            move |window, cx| {
23545                                Tooltip::for_action_in(
23546                                    "Next Hunk",
23547                                    &GoToHunk,
23548                                    &focus_handle,
23549                                    window,
23550                                    cx,
23551                                )
23552                            }
23553                        })
23554                        .on_click({
23555                            let editor = editor.clone();
23556                            move |_event, window, cx| {
23557                                editor.update(cx, |editor, cx| {
23558                                    let snapshot = editor.snapshot(window, cx);
23559                                    let position =
23560                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23561                                    editor.go_to_hunk_before_or_after_position(
23562                                        &snapshot,
23563                                        position,
23564                                        Direction::Next,
23565                                        window,
23566                                        cx,
23567                                    );
23568                                    editor.expand_selected_diff_hunks(cx);
23569                                });
23570                            }
23571                        }),
23572                )
23573                .child(
23574                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23575                        .shape(IconButtonShape::Square)
23576                        .icon_size(IconSize::Small)
23577                        // .disabled(!has_multiple_hunks)
23578                        .tooltip({
23579                            let focus_handle = editor.focus_handle(cx);
23580                            move |window, cx| {
23581                                Tooltip::for_action_in(
23582                                    "Previous Hunk",
23583                                    &GoToPreviousHunk,
23584                                    &focus_handle,
23585                                    window,
23586                                    cx,
23587                                )
23588                            }
23589                        })
23590                        .on_click({
23591                            let editor = editor.clone();
23592                            move |_event, window, cx| {
23593                                editor.update(cx, |editor, cx| {
23594                                    let snapshot = editor.snapshot(window, cx);
23595                                    let point =
23596                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23597                                    editor.go_to_hunk_before_or_after_position(
23598                                        &snapshot,
23599                                        point,
23600                                        Direction::Prev,
23601                                        window,
23602                                        cx,
23603                                    );
23604                                    editor.expand_selected_diff_hunks(cx);
23605                                });
23606                            }
23607                        }),
23608                )
23609            },
23610        )
23611        .into_any_element()
23612}