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 edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionIntent, CompletionResponse,
  151    CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink,
  152    PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::breakpoint_store::Breakpoint,
  154    debugger::{
  155        breakpoint_store::{
  156            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  157            BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::{seq::SliceRandom, thread_rng};
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::TypeId,
  178    borrow::Cow,
  179    cell::{OnceCell, RefCell},
  180    cmp::{self, Ordering, Reverse},
  181    iter::Peekable,
  182    mem,
  183    num::NonZeroU32,
  184    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  185    path::{Path, PathBuf},
  186    rc::Rc,
  187    sync::{Arc, LazyLock},
  188    time::{Duration, Instant},
  189};
  190use sum_tree::TreeMap;
  191use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  192use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  193use theme::{
  194    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  195    observe_buffer_font_size_adjustment,
  196};
  197use ui::{
  198    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  199    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  200};
  201use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  202use workspace::{
  203    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  204    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  205    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  206    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  207    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  208    searchable::SearchEvent,
  209};
  210
  211use crate::{
  212    code_context_menus::CompletionsMenuSource,
  213    editor_settings::MultiCursorModifier,
  214    hover_links::{find_url, find_url_from_range},
  215    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  216};
  217
  218pub const FILE_HEADER_HEIGHT: u32 = 2;
  219pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  220pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233
  234pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  235pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  236pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  237
  238#[derive(Clone, Debug, Eq, PartialEq)]
  239pub struct LastCursorPosition {
  240    pub path: PathBuf,
  241    pub worktree_path: Arc<Path>,
  242    pub point: Point,
  243}
  244
  245pub static LAST_CURSOR_POSITION_WATCH: LazyLock<(
  246    Mutex<postage::watch::Sender<Option<LastCursorPosition>>>,
  247    postage::watch::Receiver<Option<LastCursorPosition>>,
  248)> = LazyLock::new(|| {
  249    let (sender, receiver) = postage::watch::channel();
  250    (Mutex::new(sender), receiver)
  251});
  252
  253pub type RenderDiffHunkControlsFn = Arc<
  254    dyn Fn(
  255        u32,
  256        &DiffHunkStatus,
  257        Range<Anchor>,
  258        bool,
  259        Pixels,
  260        &Entity<Editor>,
  261        &mut Window,
  262        &mut App,
  263    ) -> AnyElement,
  264>;
  265
  266enum ReportEditorEvent {
  267    Saved { auto_saved: bool },
  268    EditorOpened,
  269    ZetaTosClicked,
  270    Closed,
  271}
  272
  273impl ReportEditorEvent {
  274    pub fn event_type(&self) -> &'static str {
  275        match self {
  276            Self::Saved { .. } => "Editor Saved",
  277            Self::EditorOpened => "Editor Opened",
  278            Self::ZetaTosClicked => "Edit Prediction Provider ToS Clicked",
  279            Self::Closed => "Editor Closed",
  280        }
  281    }
  282}
  283
  284struct InlineValueCache {
  285    enabled: bool,
  286    inlays: Vec<InlayId>,
  287    refresh_task: Task<Option<()>>,
  288}
  289
  290impl InlineValueCache {
  291    fn new(enabled: bool) -> Self {
  292        Self {
  293            enabled,
  294            inlays: Vec::new(),
  295            refresh_task: Task::ready(None),
  296        }
  297    }
  298}
  299
  300#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  301pub enum InlayId {
  302    EditPrediction(usize),
  303    DebuggerValue(usize),
  304    // LSP
  305    Hint(usize),
  306    Color(usize),
  307}
  308
  309impl InlayId {
  310    fn id(&self) -> usize {
  311        match self {
  312            Self::EditPrediction(id) => *id,
  313            Self::DebuggerValue(id) => *id,
  314            Self::Hint(id) => *id,
  315            Self::Color(id) => *id,
  316        }
  317    }
  318}
  319
  320pub enum ActiveDebugLine {}
  321pub enum DebugStackFrameLine {}
  322enum DocumentHighlightRead {}
  323enum DocumentHighlightWrite {}
  324enum InputComposition {}
  325pub enum PendingInput {}
  326enum SelectedTextHighlight {}
  327
  328pub enum ConflictsOuter {}
  329pub enum ConflictsOurs {}
  330pub enum ConflictsTheirs {}
  331pub enum ConflictsOursMarker {}
  332pub enum ConflictsTheirsMarker {}
  333
  334#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  335pub enum Navigated {
  336    Yes,
  337    No,
  338}
  339
  340impl Navigated {
  341    pub fn from_bool(yes: bool) -> Navigated {
  342        if yes { Navigated::Yes } else { Navigated::No }
  343    }
  344}
  345
  346#[derive(Debug, Clone, PartialEq, Eq)]
  347enum DisplayDiffHunk {
  348    Folded {
  349        display_row: DisplayRow,
  350    },
  351    Unfolded {
  352        is_created_file: bool,
  353        diff_base_byte_range: Range<usize>,
  354        display_row_range: Range<DisplayRow>,
  355        multi_buffer_range: Range<Anchor>,
  356        status: DiffHunkStatus,
  357    },
  358}
  359
  360pub enum HideMouseCursorOrigin {
  361    TypingAction,
  362    MovementAction,
  363}
  364
  365pub fn init_settings(cx: &mut App) {
  366    EditorSettings::register(cx);
  367}
  368
  369pub fn init(cx: &mut App) {
  370    init_settings(cx);
  371
  372    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  373
  374    workspace::register_project_item::<Editor>(cx);
  375    workspace::FollowableViewRegistry::register::<Editor>(cx);
  376    workspace::register_serializable_item::<Editor>(cx);
  377
  378    cx.observe_new(
  379        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  380            workspace.register_action(Editor::new_file);
  381            workspace.register_action(Editor::new_file_vertical);
  382            workspace.register_action(Editor::new_file_horizontal);
  383            workspace.register_action(Editor::cancel_language_server_work);
  384            workspace.register_action(Editor::toggle_focus);
  385        },
  386    )
  387    .detach();
  388
  389    cx.on_action(move |_: &workspace::NewFile, cx| {
  390        let app_state = workspace::AppState::global(cx);
  391        if let Some(app_state) = app_state.upgrade() {
  392            workspace::open_new(
  393                Default::default(),
  394                app_state,
  395                cx,
  396                |workspace, window, cx| {
  397                    Editor::new_file(workspace, &Default::default(), window, cx)
  398                },
  399            )
  400            .detach();
  401        }
  402    });
  403    cx.on_action(move |_: &workspace::NewWindow, cx| {
  404        let app_state = workspace::AppState::global(cx);
  405        if let Some(app_state) = app_state.upgrade() {
  406            workspace::open_new(
  407                Default::default(),
  408                app_state,
  409                cx,
  410                |workspace, window, cx| {
  411                    cx.activate(true);
  412                    Editor::new_file(workspace, &Default::default(), window, cx)
  413                },
  414            )
  415            .detach();
  416        }
  417    });
  418}
  419
  420pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  421    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  422}
  423
  424pub trait DiagnosticRenderer {
  425    fn render_group(
  426        &self,
  427        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  428        buffer_id: BufferId,
  429        snapshot: EditorSnapshot,
  430        editor: WeakEntity<Editor>,
  431        cx: &mut App,
  432    ) -> Vec<BlockProperties<Anchor>>;
  433
  434    fn render_hover(
  435        &self,
  436        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  437        range: Range<Point>,
  438        buffer_id: BufferId,
  439        cx: &mut App,
  440    ) -> Option<Entity<markdown::Markdown>>;
  441
  442    fn open_link(
  443        &self,
  444        editor: &mut Editor,
  445        link: SharedString,
  446        window: &mut Window,
  447        cx: &mut Context<Editor>,
  448    );
  449}
  450
  451pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  452
  453impl GlobalDiagnosticRenderer {
  454    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  455        cx.try_global::<Self>().map(|g| g.0.clone())
  456    }
  457}
  458
  459impl gpui::Global for GlobalDiagnosticRenderer {}
  460pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  461    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  462}
  463
  464pub struct SearchWithinRange;
  465
  466trait InvalidationRegion {
  467    fn ranges(&self) -> &[Range<Anchor>];
  468}
  469
  470#[derive(Clone, Debug, PartialEq)]
  471pub enum SelectPhase {
  472    Begin {
  473        position: DisplayPoint,
  474        add: bool,
  475        click_count: usize,
  476    },
  477    BeginColumnar {
  478        position: DisplayPoint,
  479        reset: bool,
  480        mode: ColumnarMode,
  481        goal_column: u32,
  482    },
  483    Extend {
  484        position: DisplayPoint,
  485        click_count: usize,
  486    },
  487    Update {
  488        position: DisplayPoint,
  489        goal_column: u32,
  490        scroll_delta: gpui::Point<f32>,
  491    },
  492    End,
  493}
  494
  495#[derive(Clone, Debug, PartialEq)]
  496pub enum ColumnarMode {
  497    FromMouse,
  498    FromSelection,
  499}
  500
  501#[derive(Clone, Debug)]
  502pub enum SelectMode {
  503    Character,
  504    Word(Range<Anchor>),
  505    Line(Range<Anchor>),
  506    All,
  507}
  508
  509#[derive(Clone, PartialEq, Eq, Debug)]
  510pub enum EditorMode {
  511    SingleLine,
  512    AutoHeight {
  513        min_lines: usize,
  514        max_lines: Option<usize>,
  515    },
  516    Full {
  517        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  518        scale_ui_elements_with_buffer_font_size: bool,
  519        /// When set to `true`, the editor will render a background for the active line.
  520        show_active_line_background: bool,
  521        /// When set to `true`, the editor's height will be determined by its content.
  522        sized_by_content: bool,
  523    },
  524    Minimap {
  525        parent: WeakEntity<Editor>,
  526    },
  527}
  528
  529impl EditorMode {
  530    pub fn full() -> Self {
  531        Self::Full {
  532            scale_ui_elements_with_buffer_font_size: true,
  533            show_active_line_background: true,
  534            sized_by_content: false,
  535        }
  536    }
  537
  538    #[inline]
  539    pub fn is_full(&self) -> bool {
  540        matches!(self, Self::Full { .. })
  541    }
  542
  543    #[inline]
  544    pub fn is_single_line(&self) -> bool {
  545        matches!(self, Self::SingleLine { .. })
  546    }
  547
  548    #[inline]
  549    fn is_minimap(&self) -> bool {
  550        matches!(self, Self::Minimap { .. })
  551    }
  552}
  553
  554#[derive(Copy, Clone, Debug)]
  555pub enum SoftWrap {
  556    /// Prefer not to wrap at all.
  557    ///
  558    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  559    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  560    GitDiff,
  561    /// Prefer a single line generally, unless an overly long line is encountered.
  562    None,
  563    /// Soft wrap lines that exceed the editor width.
  564    EditorWidth,
  565    /// Soft wrap lines at the preferred line length.
  566    Column(u32),
  567    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  568    Bounded(u32),
  569}
  570
  571#[derive(Clone)]
  572pub struct EditorStyle {
  573    pub background: Hsla,
  574    pub border: Hsla,
  575    pub local_player: PlayerColor,
  576    pub text: TextStyle,
  577    pub scrollbar_width: Pixels,
  578    pub syntax: Arc<SyntaxTheme>,
  579    pub status: StatusColors,
  580    pub inlay_hints_style: HighlightStyle,
  581    pub edit_prediction_styles: EditPredictionStyles,
  582    pub unnecessary_code_fade: f32,
  583    pub show_underlines: bool,
  584}
  585
  586impl Default for EditorStyle {
  587    fn default() -> Self {
  588        Self {
  589            background: Hsla::default(),
  590            border: Hsla::default(),
  591            local_player: PlayerColor::default(),
  592            text: TextStyle::default(),
  593            scrollbar_width: Pixels::default(),
  594            syntax: Default::default(),
  595            // HACK: Status colors don't have a real default.
  596            // We should look into removing the status colors from the editor
  597            // style and retrieve them directly from the theme.
  598            status: StatusColors::dark(),
  599            inlay_hints_style: HighlightStyle::default(),
  600            edit_prediction_styles: EditPredictionStyles {
  601                insertion: HighlightStyle::default(),
  602                whitespace: HighlightStyle::default(),
  603            },
  604            unnecessary_code_fade: Default::default(),
  605            show_underlines: true,
  606        }
  607    }
  608}
  609
  610pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  611    let show_background = language_settings::language_settings(None, None, cx)
  612        .inlay_hints
  613        .show_background;
  614
  615    HighlightStyle {
  616        color: Some(cx.theme().status().hint),
  617        background_color: show_background.then(|| cx.theme().status().hint_background),
  618        ..HighlightStyle::default()
  619    }
  620}
  621
  622pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  623    EditPredictionStyles {
  624        insertion: HighlightStyle {
  625            color: Some(cx.theme().status().predictive),
  626            ..HighlightStyle::default()
  627        },
  628        whitespace: HighlightStyle {
  629            background_color: Some(cx.theme().status().created_background),
  630            ..HighlightStyle::default()
  631        },
  632    }
  633}
  634
  635type CompletionId = usize;
  636
  637pub(crate) enum EditDisplayMode {
  638    TabAccept,
  639    DiffPopover,
  640    Inline,
  641}
  642
  643enum EditPrediction {
  644    Edit {
  645        edits: Vec<(Range<Anchor>, String)>,
  646        edit_preview: Option<EditPreview>,
  647        display_mode: EditDisplayMode,
  648        snapshot: BufferSnapshot,
  649    },
  650    Move {
  651        target: Anchor,
  652        snapshot: BufferSnapshot,
  653    },
  654}
  655
  656struct EditPredictionState {
  657    inlay_ids: Vec<InlayId>,
  658    completion: EditPrediction,
  659    completion_id: Option<SharedString>,
  660    invalidation_range: Range<Anchor>,
  661}
  662
  663enum EditPredictionSettings {
  664    Disabled,
  665    Enabled {
  666        show_in_menu: bool,
  667        preview_requires_modifier: bool,
  668    },
  669}
  670
  671enum EditPredictionHighlight {}
  672
  673#[derive(Debug, Clone)]
  674struct InlineDiagnostic {
  675    message: SharedString,
  676    group_id: usize,
  677    is_primary: bool,
  678    start: Point,
  679    severity: lsp::DiagnosticSeverity,
  680}
  681
  682pub enum MenuEditPredictionsPolicy {
  683    Never,
  684    ByProvider,
  685}
  686
  687pub enum EditPredictionPreview {
  688    /// Modifier is not pressed
  689    Inactive { released_too_fast: bool },
  690    /// Modifier pressed
  691    Active {
  692        since: Instant,
  693        previous_scroll_position: Option<ScrollAnchor>,
  694    },
  695}
  696
  697impl EditPredictionPreview {
  698    pub fn released_too_fast(&self) -> bool {
  699        match self {
  700            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  701            EditPredictionPreview::Active { .. } => false,
  702        }
  703    }
  704
  705    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  706        if let EditPredictionPreview::Active {
  707            previous_scroll_position,
  708            ..
  709        } = self
  710        {
  711            *previous_scroll_position = scroll_position;
  712        }
  713    }
  714}
  715
  716pub struct ContextMenuOptions {
  717    pub min_entries_visible: usize,
  718    pub max_entries_visible: usize,
  719    pub placement: Option<ContextMenuPlacement>,
  720}
  721
  722#[derive(Debug, Clone, PartialEq, Eq)]
  723pub enum ContextMenuPlacement {
  724    Above,
  725    Below,
  726}
  727
  728#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  729struct EditorActionId(usize);
  730
  731impl EditorActionId {
  732    pub fn post_inc(&mut self) -> Self {
  733        let answer = self.0;
  734
  735        *self = Self(answer + 1);
  736
  737        Self(answer)
  738    }
  739}
  740
  741// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  742// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  743
  744type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  745type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  746
  747#[derive(Default)]
  748struct ScrollbarMarkerState {
  749    scrollbar_size: Size<Pixels>,
  750    dirty: bool,
  751    markers: Arc<[PaintQuad]>,
  752    pending_refresh: Option<Task<Result<()>>>,
  753}
  754
  755impl ScrollbarMarkerState {
  756    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  757        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  758    }
  759}
  760
  761#[derive(Clone, Copy, PartialEq, Eq)]
  762pub enum MinimapVisibility {
  763    Disabled,
  764    Enabled {
  765        /// The configuration currently present in the users settings.
  766        setting_configuration: bool,
  767        /// Whether to override the currently set visibility from the users setting.
  768        toggle_override: bool,
  769    },
  770}
  771
  772impl MinimapVisibility {
  773    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  774        if mode.is_full() {
  775            Self::Enabled {
  776                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  777                toggle_override: false,
  778            }
  779        } else {
  780            Self::Disabled
  781        }
  782    }
  783
  784    fn hidden(&self) -> Self {
  785        match *self {
  786            Self::Enabled {
  787                setting_configuration,
  788                ..
  789            } => Self::Enabled {
  790                setting_configuration,
  791                toggle_override: setting_configuration,
  792            },
  793            Self::Disabled => Self::Disabled,
  794        }
  795    }
  796
  797    fn disabled(&self) -> bool {
  798        match *self {
  799            Self::Disabled => true,
  800            _ => false,
  801        }
  802    }
  803
  804    fn settings_visibility(&self) -> bool {
  805        match *self {
  806            Self::Enabled {
  807                setting_configuration,
  808                ..
  809            } => setting_configuration,
  810            _ => false,
  811        }
  812    }
  813
  814    fn visible(&self) -> bool {
  815        match *self {
  816            Self::Enabled {
  817                setting_configuration,
  818                toggle_override,
  819            } => setting_configuration ^ toggle_override,
  820            _ => false,
  821        }
  822    }
  823
  824    fn toggle_visibility(&self) -> Self {
  825        match *self {
  826            Self::Enabled {
  827                toggle_override,
  828                setting_configuration,
  829            } => Self::Enabled {
  830                setting_configuration,
  831                toggle_override: !toggle_override,
  832            },
  833            Self::Disabled => Self::Disabled,
  834        }
  835    }
  836}
  837
  838#[derive(Clone, Debug)]
  839struct RunnableTasks {
  840    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  841    offset: multi_buffer::Anchor,
  842    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  843    column: u32,
  844    // Values of all named captures, including those starting with '_'
  845    extra_variables: HashMap<String, String>,
  846    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  847    context_range: Range<BufferOffset>,
  848}
  849
  850impl RunnableTasks {
  851    fn resolve<'a>(
  852        &'a self,
  853        cx: &'a task::TaskContext,
  854    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  855        self.templates.iter().filter_map(|(kind, template)| {
  856            template
  857                .resolve_task(&kind.to_id_base(), cx)
  858                .map(|task| (kind.clone(), task))
  859        })
  860    }
  861}
  862
  863#[derive(Clone)]
  864pub struct ResolvedTasks {
  865    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  866    position: Anchor,
  867}
  868
  869#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  870struct BufferOffset(usize);
  871
  872// Addons allow storing per-editor state in other crates (e.g. Vim)
  873pub trait Addon: 'static {
  874    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  875
  876    fn render_buffer_header_controls(
  877        &self,
  878        _: &ExcerptInfo,
  879        _: &Window,
  880        _: &App,
  881    ) -> Option<AnyElement> {
  882        None
  883    }
  884
  885    fn to_any(&self) -> &dyn std::any::Any;
  886
  887    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  888        None
  889    }
  890}
  891
  892struct ChangeLocation {
  893    current: Option<Vec<Anchor>>,
  894    original: Vec<Anchor>,
  895}
  896impl ChangeLocation {
  897    fn locations(&self) -> &[Anchor] {
  898        self.current.as_ref().unwrap_or(&self.original)
  899    }
  900}
  901
  902/// A set of caret positions, registered when the editor was edited.
  903pub struct ChangeList {
  904    changes: Vec<ChangeLocation>,
  905    /// Currently "selected" change.
  906    position: Option<usize>,
  907}
  908
  909impl ChangeList {
  910    pub fn new() -> Self {
  911        Self {
  912            changes: Vec::new(),
  913            position: None,
  914        }
  915    }
  916
  917    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  918    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  919    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  920        if self.changes.is_empty() {
  921            return None;
  922        }
  923
  924        let prev = self.position.unwrap_or(self.changes.len());
  925        let next = if direction == Direction::Prev {
  926            prev.saturating_sub(count)
  927        } else {
  928            (prev + count).min(self.changes.len() - 1)
  929        };
  930        self.position = Some(next);
  931        self.changes.get(next).map(|change| change.locations())
  932    }
  933
  934    /// Adds a new change to the list, resetting the change list position.
  935    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  936        self.position.take();
  937        if let Some(last) = self.changes.last_mut()
  938            && group
  939        {
  940            last.current = Some(new_positions)
  941        } else {
  942            self.changes.push(ChangeLocation {
  943                original: new_positions,
  944                current: None,
  945            });
  946        }
  947    }
  948
  949    pub fn last(&self) -> Option<&[Anchor]> {
  950        self.changes.last().map(|change| change.locations())
  951    }
  952
  953    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  954        self.changes.last().map(|change| change.original.as_slice())
  955    }
  956
  957    pub fn invert_last_group(&mut self) {
  958        if let Some(last) = self.changes.last_mut()
  959            && let Some(current) = last.current.as_mut()
  960        {
  961            mem::swap(&mut last.original, current);
  962        }
  963    }
  964}
  965
  966#[derive(Clone)]
  967struct InlineBlamePopoverState {
  968    scroll_handle: ScrollHandle,
  969    commit_message: Option<ParsedCommitMessage>,
  970    markdown: Entity<Markdown>,
  971}
  972
  973struct InlineBlamePopover {
  974    position: gpui::Point<Pixels>,
  975    hide_task: Option<Task<()>>,
  976    popover_bounds: Option<Bounds<Pixels>>,
  977    popover_state: InlineBlamePopoverState,
  978    keyboard_grace: bool,
  979}
  980
  981enum SelectionDragState {
  982    /// State when no drag related activity is detected.
  983    None,
  984    /// State when the mouse is down on a selection that is about to be dragged.
  985    ReadyToDrag {
  986        selection: Selection<Anchor>,
  987        click_position: gpui::Point<Pixels>,
  988        mouse_down_time: Instant,
  989    },
  990    /// State when the mouse is dragging the selection in the editor.
  991    Dragging {
  992        selection: Selection<Anchor>,
  993        drop_cursor: Selection<Anchor>,
  994        hide_drop_cursor: bool,
  995    },
  996}
  997
  998enum ColumnarSelectionState {
  999    FromMouse {
 1000        selection_tail: Anchor,
 1001        display_point: Option<DisplayPoint>,
 1002    },
 1003    FromSelection {
 1004        selection_tail: Anchor,
 1005    },
 1006}
 1007
 1008/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1009/// a breakpoint on them.
 1010#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1011struct PhantomBreakpointIndicator {
 1012    display_row: DisplayRow,
 1013    /// There's a small debounce between hovering over the line and showing the indicator.
 1014    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1015    is_active: bool,
 1016    collides_with_existing_breakpoint: bool,
 1017}
 1018
 1019/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1020///
 1021/// See the [module level documentation](self) for more information.
 1022pub struct Editor {
 1023    focus_handle: FocusHandle,
 1024    last_focused_descendant: Option<WeakFocusHandle>,
 1025    /// The text buffer being edited
 1026    buffer: Entity<MultiBuffer>,
 1027    /// Map of how text in the buffer should be displayed.
 1028    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1029    pub display_map: Entity<DisplayMap>,
 1030    pub selections: SelectionsCollection,
 1031    pub scroll_manager: ScrollManager,
 1032    /// When inline assist editors are linked, they all render cursors because
 1033    /// typing enters text into each of them, even the ones that aren't focused.
 1034    pub(crate) show_cursor_when_unfocused: bool,
 1035    columnar_selection_state: Option<ColumnarSelectionState>,
 1036    add_selections_state: Option<AddSelectionsState>,
 1037    select_next_state: Option<SelectNextState>,
 1038    select_prev_state: Option<SelectNextState>,
 1039    selection_history: SelectionHistory,
 1040    defer_selection_effects: bool,
 1041    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1042    autoclose_regions: Vec<AutocloseRegion>,
 1043    snippet_stack: InvalidationStack<SnippetState>,
 1044    select_syntax_node_history: SelectSyntaxNodeHistory,
 1045    ime_transaction: Option<TransactionId>,
 1046    pub diagnostics_max_severity: DiagnosticSeverity,
 1047    active_diagnostics: ActiveDiagnostic,
 1048    show_inline_diagnostics: bool,
 1049    inline_diagnostics_update: Task<()>,
 1050    inline_diagnostics_enabled: bool,
 1051    diagnostics_enabled: bool,
 1052    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1053    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1054    hard_wrap: Option<usize>,
 1055    project: Option<Entity<Project>>,
 1056    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1057    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1058    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1059    blink_manager: Entity<BlinkManager>,
 1060    show_cursor_names: bool,
 1061    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1062    pub show_local_selections: bool,
 1063    mode: EditorMode,
 1064    show_breadcrumbs: bool,
 1065    show_gutter: bool,
 1066    show_scrollbars: ScrollbarAxes,
 1067    minimap_visibility: MinimapVisibility,
 1068    offset_content: bool,
 1069    disable_expand_excerpt_buttons: bool,
 1070    show_line_numbers: Option<bool>,
 1071    use_relative_line_numbers: Option<bool>,
 1072    show_git_diff_gutter: Option<bool>,
 1073    show_code_actions: Option<bool>,
 1074    show_runnables: Option<bool>,
 1075    show_breakpoints: Option<bool>,
 1076    show_wrap_guides: Option<bool>,
 1077    show_indent_guides: Option<bool>,
 1078    placeholder_text: Option<Arc<str>>,
 1079    highlight_order: usize,
 1080    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1081    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1082    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1083    scrollbar_marker_state: ScrollbarMarkerState,
 1084    active_indent_guides_state: ActiveIndentGuidesState,
 1085    nav_history: Option<ItemNavHistory>,
 1086    context_menu: RefCell<Option<CodeContextMenu>>,
 1087    context_menu_options: Option<ContextMenuOptions>,
 1088    mouse_context_menu: Option<MouseContextMenu>,
 1089    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1090    inline_blame_popover: Option<InlineBlamePopover>,
 1091    inline_blame_popover_show_task: Option<Task<()>>,
 1092    signature_help_state: SignatureHelpState,
 1093    auto_signature_help: Option<bool>,
 1094    find_all_references_task_sources: Vec<Anchor>,
 1095    next_completion_id: CompletionId,
 1096    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1097    code_actions_task: Option<Task<Result<()>>>,
 1098    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1099    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1100    document_highlights_task: Option<Task<()>>,
 1101    linked_editing_range_task: Option<Task<Option<()>>>,
 1102    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1103    pending_rename: Option<RenameState>,
 1104    searchable: bool,
 1105    cursor_shape: CursorShape,
 1106    current_line_highlight: Option<CurrentLineHighlight>,
 1107    collapse_matches: bool,
 1108    autoindent_mode: Option<AutoindentMode>,
 1109    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1110    input_enabled: bool,
 1111    use_modal_editing: bool,
 1112    read_only: bool,
 1113    leader_id: Option<CollaboratorId>,
 1114    remote_id: Option<ViewId>,
 1115    pub hover_state: HoverState,
 1116    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1117    gutter_hovered: bool,
 1118    hovered_link_state: Option<HoveredLinkState>,
 1119    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1120    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1121    active_edit_prediction: Option<EditPredictionState>,
 1122    /// Used to prevent flickering as the user types while the menu is open
 1123    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1124    edit_prediction_settings: EditPredictionSettings,
 1125    edit_predictions_hidden_for_vim_mode: bool,
 1126    show_edit_predictions_override: Option<bool>,
 1127    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1128    edit_prediction_preview: EditPredictionPreview,
 1129    edit_prediction_indent_conflict: bool,
 1130    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1131    inlay_hint_cache: InlayHintCache,
 1132    next_inlay_id: usize,
 1133    _subscriptions: Vec<Subscription>,
 1134    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1135    gutter_dimensions: GutterDimensions,
 1136    style: Option<EditorStyle>,
 1137    text_style_refinement: Option<TextStyleRefinement>,
 1138    next_editor_action_id: EditorActionId,
 1139    editor_actions: Rc<
 1140        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1141    >,
 1142    use_autoclose: bool,
 1143    use_auto_surround: bool,
 1144    auto_replace_emoji_shortcode: bool,
 1145    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1146    show_git_blame_gutter: bool,
 1147    show_git_blame_inline: bool,
 1148    show_git_blame_inline_delay_task: Option<Task<()>>,
 1149    git_blame_inline_enabled: bool,
 1150    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1151    serialize_dirty_buffers: bool,
 1152    show_selection_menu: Option<bool>,
 1153    blame: Option<Entity<GitBlame>>,
 1154    blame_subscription: Option<Subscription>,
 1155    custom_context_menu: Option<
 1156        Box<
 1157            dyn 'static
 1158                + Fn(
 1159                    &mut Self,
 1160                    DisplayPoint,
 1161                    &mut Window,
 1162                    &mut Context<Self>,
 1163                ) -> Option<Entity<ui::ContextMenu>>,
 1164        >,
 1165    >,
 1166    last_bounds: Option<Bounds<Pixels>>,
 1167    last_position_map: Option<Rc<PositionMap>>,
 1168    expect_bounds_change: Option<Bounds<Pixels>>,
 1169    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1170    tasks_update_task: Option<Task<()>>,
 1171    breakpoint_store: Option<Entity<BreakpointStore>>,
 1172    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1173    hovered_diff_hunk_row: Option<DisplayRow>,
 1174    pull_diagnostics_task: Task<()>,
 1175    in_project_search: bool,
 1176    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1177    breadcrumb_header: Option<String>,
 1178    focused_block: Option<FocusedBlock>,
 1179    next_scroll_position: NextScrollCursorCenterTopBottom,
 1180    addons: HashMap<TypeId, Box<dyn Addon>>,
 1181    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1182    load_diff_task: Option<Shared<Task<()>>>,
 1183    /// Whether we are temporarily displaying a diff other than git's
 1184    temporary_diff_override: bool,
 1185    selection_mark_mode: bool,
 1186    toggle_fold_multiple_buffers: Task<()>,
 1187    _scroll_cursor_center_top_bottom_task: Task<()>,
 1188    serialize_selections: Task<()>,
 1189    serialize_folds: Task<()>,
 1190    mouse_cursor_hidden: bool,
 1191    minimap: Option<Entity<Self>>,
 1192    hide_mouse_mode: HideMouseMode,
 1193    pub change_list: ChangeList,
 1194    inline_value_cache: InlineValueCache,
 1195    selection_drag_state: SelectionDragState,
 1196    next_color_inlay_id: usize,
 1197    colors: Option<LspColorData>,
 1198    folding_newlines: Task<()>,
 1199}
 1200
 1201#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1202enum NextScrollCursorCenterTopBottom {
 1203    #[default]
 1204    Center,
 1205    Top,
 1206    Bottom,
 1207}
 1208
 1209impl NextScrollCursorCenterTopBottom {
 1210    fn next(&self) -> Self {
 1211        match self {
 1212            Self::Center => Self::Top,
 1213            Self::Top => Self::Bottom,
 1214            Self::Bottom => Self::Center,
 1215        }
 1216    }
 1217}
 1218
 1219#[derive(Clone)]
 1220pub struct EditorSnapshot {
 1221    pub mode: EditorMode,
 1222    show_gutter: bool,
 1223    show_line_numbers: Option<bool>,
 1224    show_git_diff_gutter: Option<bool>,
 1225    show_code_actions: Option<bool>,
 1226    show_runnables: Option<bool>,
 1227    show_breakpoints: Option<bool>,
 1228    git_blame_gutter_max_author_length: Option<usize>,
 1229    pub display_snapshot: DisplaySnapshot,
 1230    pub placeholder_text: Option<Arc<str>>,
 1231    is_focused: bool,
 1232    scroll_anchor: ScrollAnchor,
 1233    ongoing_scroll: OngoingScroll,
 1234    current_line_highlight: CurrentLineHighlight,
 1235    gutter_hovered: bool,
 1236}
 1237
 1238#[derive(Default, Debug, Clone, Copy)]
 1239pub struct GutterDimensions {
 1240    pub left_padding: Pixels,
 1241    pub right_padding: Pixels,
 1242    pub width: Pixels,
 1243    pub margin: Pixels,
 1244    pub git_blame_entries_width: Option<Pixels>,
 1245}
 1246
 1247impl GutterDimensions {
 1248    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1249        Self {
 1250            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1251            ..Default::default()
 1252        }
 1253    }
 1254
 1255    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1256        -cx.text_system().descent(font_id, font_size)
 1257    }
 1258    /// The full width of the space taken up by the gutter.
 1259    pub fn full_width(&self) -> Pixels {
 1260        self.margin + self.width
 1261    }
 1262
 1263    /// The width of the space reserved for the fold indicators,
 1264    /// use alongside 'justify_end' and `gutter_width` to
 1265    /// right align content with the line numbers
 1266    pub fn fold_area_width(&self) -> Pixels {
 1267        self.margin + self.right_padding
 1268    }
 1269}
 1270
 1271struct CharacterDimensions {
 1272    em_width: Pixels,
 1273    em_advance: Pixels,
 1274    line_height: Pixels,
 1275}
 1276
 1277#[derive(Debug)]
 1278pub struct RemoteSelection {
 1279    pub replica_id: ReplicaId,
 1280    pub selection: Selection<Anchor>,
 1281    pub cursor_shape: CursorShape,
 1282    pub collaborator_id: CollaboratorId,
 1283    pub line_mode: bool,
 1284    pub user_name: Option<SharedString>,
 1285    pub color: PlayerColor,
 1286}
 1287
 1288#[derive(Clone, Debug)]
 1289struct SelectionHistoryEntry {
 1290    selections: Arc<[Selection<Anchor>]>,
 1291    select_next_state: Option<SelectNextState>,
 1292    select_prev_state: Option<SelectNextState>,
 1293    add_selections_state: Option<AddSelectionsState>,
 1294}
 1295
 1296#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1297enum SelectionHistoryMode {
 1298    Normal,
 1299    Undoing,
 1300    Redoing,
 1301    Skipping,
 1302}
 1303
 1304#[derive(Clone, PartialEq, Eq, Hash)]
 1305struct HoveredCursor {
 1306    replica_id: u16,
 1307    selection_id: usize,
 1308}
 1309
 1310impl Default for SelectionHistoryMode {
 1311    fn default() -> Self {
 1312        Self::Normal
 1313    }
 1314}
 1315
 1316#[derive(Debug)]
 1317/// SelectionEffects controls the side-effects of updating the selection.
 1318///
 1319/// The default behaviour does "what you mostly want":
 1320/// - it pushes to the nav history if the cursor moved by >10 lines
 1321/// - it re-triggers completion requests
 1322/// - it scrolls to fit
 1323///
 1324/// You might want to modify these behaviours. For example when doing a "jump"
 1325/// like go to definition, we always want to add to nav history; but when scrolling
 1326/// in vim mode we never do.
 1327///
 1328/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1329/// move.
 1330#[derive(Clone)]
 1331pub struct SelectionEffects {
 1332    nav_history: Option<bool>,
 1333    completions: bool,
 1334    scroll: Option<Autoscroll>,
 1335}
 1336
 1337impl Default for SelectionEffects {
 1338    fn default() -> Self {
 1339        Self {
 1340            nav_history: None,
 1341            completions: true,
 1342            scroll: Some(Autoscroll::fit()),
 1343        }
 1344    }
 1345}
 1346impl SelectionEffects {
 1347    pub fn scroll(scroll: Autoscroll) -> Self {
 1348        Self {
 1349            scroll: Some(scroll),
 1350            ..Default::default()
 1351        }
 1352    }
 1353
 1354    pub fn no_scroll() -> Self {
 1355        Self {
 1356            scroll: None,
 1357            ..Default::default()
 1358        }
 1359    }
 1360
 1361    pub fn completions(self, completions: bool) -> Self {
 1362        Self {
 1363            completions,
 1364            ..self
 1365        }
 1366    }
 1367
 1368    pub fn nav_history(self, nav_history: bool) -> Self {
 1369        Self {
 1370            nav_history: Some(nav_history),
 1371            ..self
 1372        }
 1373    }
 1374}
 1375
 1376struct DeferredSelectionEffectsState {
 1377    changed: bool,
 1378    effects: SelectionEffects,
 1379    old_cursor_position: Anchor,
 1380    history_entry: SelectionHistoryEntry,
 1381}
 1382
 1383#[derive(Default)]
 1384struct SelectionHistory {
 1385    #[allow(clippy::type_complexity)]
 1386    selections_by_transaction:
 1387        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1388    mode: SelectionHistoryMode,
 1389    undo_stack: VecDeque<SelectionHistoryEntry>,
 1390    redo_stack: VecDeque<SelectionHistoryEntry>,
 1391}
 1392
 1393impl SelectionHistory {
 1394    #[track_caller]
 1395    fn insert_transaction(
 1396        &mut self,
 1397        transaction_id: TransactionId,
 1398        selections: Arc<[Selection<Anchor>]>,
 1399    ) {
 1400        if selections.is_empty() {
 1401            log::error!(
 1402                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1403                std::panic::Location::caller()
 1404            );
 1405            return;
 1406        }
 1407        self.selections_by_transaction
 1408            .insert(transaction_id, (selections, None));
 1409    }
 1410
 1411    #[allow(clippy::type_complexity)]
 1412    fn transaction(
 1413        &self,
 1414        transaction_id: TransactionId,
 1415    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1416        self.selections_by_transaction.get(&transaction_id)
 1417    }
 1418
 1419    #[allow(clippy::type_complexity)]
 1420    fn transaction_mut(
 1421        &mut self,
 1422        transaction_id: TransactionId,
 1423    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1424        self.selections_by_transaction.get_mut(&transaction_id)
 1425    }
 1426
 1427    fn push(&mut self, entry: SelectionHistoryEntry) {
 1428        if !entry.selections.is_empty() {
 1429            match self.mode {
 1430                SelectionHistoryMode::Normal => {
 1431                    self.push_undo(entry);
 1432                    self.redo_stack.clear();
 1433                }
 1434                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1435                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1436                SelectionHistoryMode::Skipping => {}
 1437            }
 1438        }
 1439    }
 1440
 1441    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1442        if self
 1443            .undo_stack
 1444            .back()
 1445            .is_none_or(|e| e.selections != entry.selections)
 1446        {
 1447            self.undo_stack.push_back(entry);
 1448            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1449                self.undo_stack.pop_front();
 1450            }
 1451        }
 1452    }
 1453
 1454    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1455        if self
 1456            .redo_stack
 1457            .back()
 1458            .is_none_or(|e| e.selections != entry.selections)
 1459        {
 1460            self.redo_stack.push_back(entry);
 1461            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1462                self.redo_stack.pop_front();
 1463            }
 1464        }
 1465    }
 1466}
 1467
 1468#[derive(Clone, Copy)]
 1469pub struct RowHighlightOptions {
 1470    pub autoscroll: bool,
 1471    pub include_gutter: bool,
 1472}
 1473
 1474impl Default for RowHighlightOptions {
 1475    fn default() -> Self {
 1476        Self {
 1477            autoscroll: Default::default(),
 1478            include_gutter: true,
 1479        }
 1480    }
 1481}
 1482
 1483struct RowHighlight {
 1484    index: usize,
 1485    range: Range<Anchor>,
 1486    color: Hsla,
 1487    options: RowHighlightOptions,
 1488    type_id: TypeId,
 1489}
 1490
 1491#[derive(Clone, Debug)]
 1492struct AddSelectionsState {
 1493    groups: Vec<AddSelectionsGroup>,
 1494}
 1495
 1496#[derive(Clone, Debug)]
 1497struct AddSelectionsGroup {
 1498    above: bool,
 1499    stack: Vec<usize>,
 1500}
 1501
 1502#[derive(Clone)]
 1503struct SelectNextState {
 1504    query: AhoCorasick,
 1505    wordwise: bool,
 1506    done: bool,
 1507}
 1508
 1509impl std::fmt::Debug for SelectNextState {
 1510    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1511        f.debug_struct(std::any::type_name::<Self>())
 1512            .field("wordwise", &self.wordwise)
 1513            .field("done", &self.done)
 1514            .finish()
 1515    }
 1516}
 1517
 1518#[derive(Debug)]
 1519struct AutocloseRegion {
 1520    selection_id: usize,
 1521    range: Range<Anchor>,
 1522    pair: BracketPair,
 1523}
 1524
 1525#[derive(Debug)]
 1526struct SnippetState {
 1527    ranges: Vec<Vec<Range<Anchor>>>,
 1528    active_index: usize,
 1529    choices: Vec<Option<Vec<String>>>,
 1530}
 1531
 1532#[doc(hidden)]
 1533pub struct RenameState {
 1534    pub range: Range<Anchor>,
 1535    pub old_name: Arc<str>,
 1536    pub editor: Entity<Editor>,
 1537    block_id: CustomBlockId,
 1538}
 1539
 1540struct InvalidationStack<T>(Vec<T>);
 1541
 1542struct RegisteredEditPredictionProvider {
 1543    provider: Arc<dyn EditPredictionProviderHandle>,
 1544    _subscription: Subscription,
 1545}
 1546
 1547#[derive(Debug, PartialEq, Eq)]
 1548pub struct ActiveDiagnosticGroup {
 1549    pub active_range: Range<Anchor>,
 1550    pub active_message: String,
 1551    pub group_id: usize,
 1552    pub blocks: HashSet<CustomBlockId>,
 1553}
 1554
 1555#[derive(Debug, PartialEq, Eq)]
 1556
 1557pub(crate) enum ActiveDiagnostic {
 1558    None,
 1559    All,
 1560    Group(ActiveDiagnosticGroup),
 1561}
 1562
 1563#[derive(Serialize, Deserialize, Clone, Debug)]
 1564pub struct ClipboardSelection {
 1565    /// The number of bytes in this selection.
 1566    pub len: usize,
 1567    /// Whether this was a full-line selection.
 1568    pub is_entire_line: bool,
 1569    /// The indentation of the first line when this content was originally copied.
 1570    pub first_line_indent: u32,
 1571}
 1572
 1573// selections, scroll behavior, was newest selection reversed
 1574type SelectSyntaxNodeHistoryState = (
 1575    Box<[Selection<usize>]>,
 1576    SelectSyntaxNodeScrollBehavior,
 1577    bool,
 1578);
 1579
 1580#[derive(Default)]
 1581struct SelectSyntaxNodeHistory {
 1582    stack: Vec<SelectSyntaxNodeHistoryState>,
 1583    // disable temporarily to allow changing selections without losing the stack
 1584    pub disable_clearing: bool,
 1585}
 1586
 1587impl SelectSyntaxNodeHistory {
 1588    pub fn try_clear(&mut self) {
 1589        if !self.disable_clearing {
 1590            self.stack.clear();
 1591        }
 1592    }
 1593
 1594    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1595        self.stack.push(selection);
 1596    }
 1597
 1598    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1599        self.stack.pop()
 1600    }
 1601}
 1602
 1603enum SelectSyntaxNodeScrollBehavior {
 1604    CursorTop,
 1605    FitSelection,
 1606    CursorBottom,
 1607}
 1608
 1609#[derive(Debug)]
 1610pub(crate) struct NavigationData {
 1611    cursor_anchor: Anchor,
 1612    cursor_position: Point,
 1613    scroll_anchor: ScrollAnchor,
 1614    scroll_top_row: u32,
 1615}
 1616
 1617#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1618pub enum GotoDefinitionKind {
 1619    Symbol,
 1620    Declaration,
 1621    Type,
 1622    Implementation,
 1623}
 1624
 1625#[derive(Debug, Clone)]
 1626enum InlayHintRefreshReason {
 1627    ModifiersChanged(bool),
 1628    Toggle(bool),
 1629    SettingsChange(InlayHintSettings),
 1630    NewLinesShown,
 1631    BufferEdited(HashSet<Arc<Language>>),
 1632    RefreshRequested,
 1633    ExcerptsRemoved(Vec<ExcerptId>),
 1634}
 1635
 1636impl InlayHintRefreshReason {
 1637    fn description(&self) -> &'static str {
 1638        match self {
 1639            Self::ModifiersChanged(_) => "modifiers changed",
 1640            Self::Toggle(_) => "toggle",
 1641            Self::SettingsChange(_) => "settings change",
 1642            Self::NewLinesShown => "new lines shown",
 1643            Self::BufferEdited(_) => "buffer edited",
 1644            Self::RefreshRequested => "refresh requested",
 1645            Self::ExcerptsRemoved(_) => "excerpts removed",
 1646        }
 1647    }
 1648}
 1649
 1650pub enum FormatTarget {
 1651    Buffers(HashSet<Entity<Buffer>>),
 1652    Ranges(Vec<Range<MultiBufferPoint>>),
 1653}
 1654
 1655pub(crate) struct FocusedBlock {
 1656    id: BlockId,
 1657    focus_handle: WeakFocusHandle,
 1658}
 1659
 1660#[derive(Clone)]
 1661enum JumpData {
 1662    MultiBufferRow {
 1663        row: MultiBufferRow,
 1664        line_offset_from_top: u32,
 1665    },
 1666    MultiBufferPoint {
 1667        excerpt_id: ExcerptId,
 1668        position: Point,
 1669        anchor: text::Anchor,
 1670        line_offset_from_top: u32,
 1671    },
 1672}
 1673
 1674pub enum MultibufferSelectionMode {
 1675    First,
 1676    All,
 1677}
 1678
 1679#[derive(Clone, Copy, Debug, Default)]
 1680pub struct RewrapOptions {
 1681    pub override_language_settings: bool,
 1682    pub preserve_existing_whitespace: bool,
 1683}
 1684
 1685impl Editor {
 1686    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1687        let buffer = cx.new(|cx| Buffer::local("", cx));
 1688        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1689        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1690    }
 1691
 1692    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1693        let buffer = cx.new(|cx| Buffer::local("", cx));
 1694        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1695        Self::new(EditorMode::full(), buffer, None, window, cx)
 1696    }
 1697
 1698    pub fn auto_height(
 1699        min_lines: usize,
 1700        max_lines: usize,
 1701        window: &mut Window,
 1702        cx: &mut Context<Self>,
 1703    ) -> Self {
 1704        let buffer = cx.new(|cx| Buffer::local("", cx));
 1705        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1706        Self::new(
 1707            EditorMode::AutoHeight {
 1708                min_lines,
 1709                max_lines: Some(max_lines),
 1710            },
 1711            buffer,
 1712            None,
 1713            window,
 1714            cx,
 1715        )
 1716    }
 1717
 1718    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1719    /// The editor grows as tall as needed to fit its content.
 1720    pub fn auto_height_unbounded(
 1721        min_lines: usize,
 1722        window: &mut Window,
 1723        cx: &mut Context<Self>,
 1724    ) -> Self {
 1725        let buffer = cx.new(|cx| Buffer::local("", cx));
 1726        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1727        Self::new(
 1728            EditorMode::AutoHeight {
 1729                min_lines,
 1730                max_lines: None,
 1731            },
 1732            buffer,
 1733            None,
 1734            window,
 1735            cx,
 1736        )
 1737    }
 1738
 1739    pub fn for_buffer(
 1740        buffer: Entity<Buffer>,
 1741        project: Option<Entity<Project>>,
 1742        window: &mut Window,
 1743        cx: &mut Context<Self>,
 1744    ) -> Self {
 1745        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1746        Self::new(EditorMode::full(), buffer, project, window, cx)
 1747    }
 1748
 1749    pub fn for_multibuffer(
 1750        buffer: Entity<MultiBuffer>,
 1751        project: Option<Entity<Project>>,
 1752        window: &mut Window,
 1753        cx: &mut Context<Self>,
 1754    ) -> Self {
 1755        Self::new(EditorMode::full(), buffer, project, window, cx)
 1756    }
 1757
 1758    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1759        let mut clone = Self::new(
 1760            self.mode.clone(),
 1761            self.buffer.clone(),
 1762            self.project.clone(),
 1763            window,
 1764            cx,
 1765        );
 1766        self.display_map.update(cx, |display_map, cx| {
 1767            let snapshot = display_map.snapshot(cx);
 1768            clone.display_map.update(cx, |display_map, cx| {
 1769                display_map.set_state(&snapshot, cx);
 1770            });
 1771        });
 1772        clone.folds_did_change(cx);
 1773        clone.selections.clone_state(&self.selections);
 1774        clone.scroll_manager.clone_state(&self.scroll_manager);
 1775        clone.searchable = self.searchable;
 1776        clone.read_only = self.read_only;
 1777        clone
 1778    }
 1779
 1780    pub fn new(
 1781        mode: EditorMode,
 1782        buffer: Entity<MultiBuffer>,
 1783        project: Option<Entity<Project>>,
 1784        window: &mut Window,
 1785        cx: &mut Context<Self>,
 1786    ) -> Self {
 1787        Editor::new_internal(mode, buffer, project, None, window, cx)
 1788    }
 1789
 1790    fn new_internal(
 1791        mode: EditorMode,
 1792        buffer: Entity<MultiBuffer>,
 1793        project: Option<Entity<Project>>,
 1794        display_map: Option<Entity<DisplayMap>>,
 1795        window: &mut Window,
 1796        cx: &mut Context<Self>,
 1797    ) -> Self {
 1798        debug_assert!(
 1799            display_map.is_none() || mode.is_minimap(),
 1800            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1801        );
 1802
 1803        let full_mode = mode.is_full();
 1804        let is_minimap = mode.is_minimap();
 1805        let diagnostics_max_severity = if full_mode {
 1806            EditorSettings::get_global(cx)
 1807                .diagnostics_max_severity
 1808                .unwrap_or(DiagnosticSeverity::Hint)
 1809        } else {
 1810            DiagnosticSeverity::Off
 1811        };
 1812        let style = window.text_style();
 1813        let font_size = style.font_size.to_pixels(window.rem_size());
 1814        let editor = cx.entity().downgrade();
 1815        let fold_placeholder = FoldPlaceholder {
 1816            constrain_width: true,
 1817            render: Arc::new(move |fold_id, fold_range, cx| {
 1818                let editor = editor.clone();
 1819                div()
 1820                    .id(fold_id)
 1821                    .bg(cx.theme().colors().ghost_element_background)
 1822                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1823                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1824                    .rounded_xs()
 1825                    .size_full()
 1826                    .cursor_pointer()
 1827                    .child("")
 1828                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1829                    .on_click(move |_, _window, cx| {
 1830                        editor
 1831                            .update(cx, |editor, cx| {
 1832                                editor.unfold_ranges(
 1833                                    &[fold_range.start..fold_range.end],
 1834                                    true,
 1835                                    false,
 1836                                    cx,
 1837                                );
 1838                                cx.stop_propagation();
 1839                            })
 1840                            .ok();
 1841                    })
 1842                    .into_any()
 1843            }),
 1844            merge_adjacent: true,
 1845            ..FoldPlaceholder::default()
 1846        };
 1847        let display_map = display_map.unwrap_or_else(|| {
 1848            cx.new(|cx| {
 1849                DisplayMap::new(
 1850                    buffer.clone(),
 1851                    style.font(),
 1852                    font_size,
 1853                    None,
 1854                    FILE_HEADER_HEIGHT,
 1855                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1856                    fold_placeholder,
 1857                    diagnostics_max_severity,
 1858                    cx,
 1859                )
 1860            })
 1861        });
 1862
 1863        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1864
 1865        let blink_manager = cx.new(|cx| {
 1866            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1867            if is_minimap {
 1868                blink_manager.disable(cx);
 1869            }
 1870            blink_manager
 1871        });
 1872
 1873        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1874            .then(|| language_settings::SoftWrap::None);
 1875
 1876        let mut project_subscriptions = Vec::new();
 1877        if full_mode && let Some(project) = project.as_ref() {
 1878            project_subscriptions.push(cx.subscribe_in(
 1879                project,
 1880                window,
 1881                |editor, _, event, window, cx| match event {
 1882                    project::Event::RefreshCodeLens => {
 1883                        // we always query lens with actions, without storing them, always refreshing them
 1884                    }
 1885                    project::Event::RefreshInlayHints => {
 1886                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1887                    }
 1888                    project::Event::LanguageServerAdded(..)
 1889                    | project::Event::LanguageServerRemoved(..) => {
 1890                        if editor.tasks_update_task.is_none() {
 1891                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1892                        }
 1893                    }
 1894                    project::Event::SnippetEdit(id, snippet_edits) => {
 1895                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1896                            let focus_handle = editor.focus_handle(cx);
 1897                            if focus_handle.is_focused(window) {
 1898                                let snapshot = buffer.read(cx).snapshot();
 1899                                for (range, snippet) in snippet_edits {
 1900                                    let editor_range =
 1901                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1902                                    editor
 1903                                        .insert_snippet(
 1904                                            &[editor_range],
 1905                                            snippet.clone(),
 1906                                            window,
 1907                                            cx,
 1908                                        )
 1909                                        .ok();
 1910                                }
 1911                            }
 1912                        }
 1913                    }
 1914                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1915                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1916                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1917                        }
 1918                    }
 1919                    _ => {}
 1920                },
 1921            ));
 1922            if let Some(task_inventory) = project
 1923                .read(cx)
 1924                .task_store()
 1925                .read(cx)
 1926                .task_inventory()
 1927                .cloned()
 1928            {
 1929                project_subscriptions.push(cx.observe_in(
 1930                    &task_inventory,
 1931                    window,
 1932                    |editor, _, window, cx| {
 1933                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1934                    },
 1935                ));
 1936            };
 1937
 1938            project_subscriptions.push(cx.subscribe_in(
 1939                &project.read(cx).breakpoint_store(),
 1940                window,
 1941                |editor, _, event, window, cx| match event {
 1942                    BreakpointStoreEvent::ClearDebugLines => {
 1943                        editor.clear_row_highlights::<ActiveDebugLine>();
 1944                        editor.refresh_inline_values(cx);
 1945                    }
 1946                    BreakpointStoreEvent::SetDebugLine => {
 1947                        if editor.go_to_active_debug_line(window, cx) {
 1948                            cx.stop_propagation();
 1949                        }
 1950
 1951                        editor.refresh_inline_values(cx);
 1952                    }
 1953                    _ => {}
 1954                },
 1955            ));
 1956            let git_store = project.read(cx).git_store().clone();
 1957            let project = project.clone();
 1958            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1959                match event {
 1960                    GitStoreEvent::RepositoryUpdated(
 1961                        _,
 1962                        RepositoryEvent::Updated {
 1963                            new_instance: true, ..
 1964                        },
 1965                        _,
 1966                    ) => {
 1967                        this.load_diff_task = Some(
 1968                            update_uncommitted_diff_for_buffer(
 1969                                cx.entity(),
 1970                                &project,
 1971                                this.buffer.read(cx).all_buffers(),
 1972                                this.buffer.clone(),
 1973                                cx,
 1974                            )
 1975                            .shared(),
 1976                        );
 1977                    }
 1978                    _ => {}
 1979                }
 1980            }));
 1981        }
 1982
 1983        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1984
 1985        let inlay_hint_settings =
 1986            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1987        let focus_handle = cx.focus_handle();
 1988        if !is_minimap {
 1989            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1990                .detach();
 1991            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1992                .detach();
 1993            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1994                .detach();
 1995            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1996                .detach();
 1997            cx.observe_pending_input(window, Self::observe_pending_input)
 1998                .detach();
 1999        }
 2000
 2001        let show_indent_guides = if matches!(
 2002            mode,
 2003            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 2004        ) {
 2005            Some(false)
 2006        } else {
 2007            None
 2008        };
 2009
 2010        let breakpoint_store = match (&mode, project.as_ref()) {
 2011            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2012            _ => None,
 2013        };
 2014
 2015        let mut code_action_providers = Vec::new();
 2016        let mut load_uncommitted_diff = None;
 2017        if let Some(project) = project.clone() {
 2018            load_uncommitted_diff = Some(
 2019                update_uncommitted_diff_for_buffer(
 2020                    cx.entity(),
 2021                    &project,
 2022                    buffer.read(cx).all_buffers(),
 2023                    buffer.clone(),
 2024                    cx,
 2025                )
 2026                .shared(),
 2027            );
 2028            code_action_providers.push(Rc::new(project) as Rc<_>);
 2029        }
 2030
 2031        let mut editor = Self {
 2032            focus_handle,
 2033            show_cursor_when_unfocused: false,
 2034            last_focused_descendant: None,
 2035            buffer: buffer.clone(),
 2036            display_map: display_map.clone(),
 2037            selections,
 2038            scroll_manager: ScrollManager::new(cx),
 2039            columnar_selection_state: None,
 2040            add_selections_state: None,
 2041            select_next_state: None,
 2042            select_prev_state: None,
 2043            selection_history: SelectionHistory::default(),
 2044            defer_selection_effects: false,
 2045            deferred_selection_effects_state: None,
 2046            autoclose_regions: Vec::new(),
 2047            snippet_stack: InvalidationStack::default(),
 2048            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2049            ime_transaction: None,
 2050            active_diagnostics: ActiveDiagnostic::None,
 2051            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2052            inline_diagnostics_update: Task::ready(()),
 2053            inline_diagnostics: Vec::new(),
 2054            soft_wrap_mode_override,
 2055            diagnostics_max_severity,
 2056            hard_wrap: None,
 2057            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2058            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2059            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2060            project,
 2061            blink_manager: blink_manager.clone(),
 2062            show_local_selections: true,
 2063            show_scrollbars: ScrollbarAxes {
 2064                horizontal: full_mode,
 2065                vertical: full_mode,
 2066            },
 2067            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2068            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2069            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2070            show_gutter: full_mode,
 2071            show_line_numbers: (!full_mode).then_some(false),
 2072            use_relative_line_numbers: None,
 2073            disable_expand_excerpt_buttons: !full_mode,
 2074            show_git_diff_gutter: None,
 2075            show_code_actions: None,
 2076            show_runnables: None,
 2077            show_breakpoints: None,
 2078            show_wrap_guides: None,
 2079            show_indent_guides,
 2080            placeholder_text: None,
 2081            highlight_order: 0,
 2082            highlighted_rows: HashMap::default(),
 2083            background_highlights: TreeMap::default(),
 2084            gutter_highlights: TreeMap::default(),
 2085            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2086            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2087            nav_history: None,
 2088            context_menu: RefCell::new(None),
 2089            context_menu_options: None,
 2090            mouse_context_menu: None,
 2091            completion_tasks: Vec::new(),
 2092            inline_blame_popover: None,
 2093            inline_blame_popover_show_task: None,
 2094            signature_help_state: SignatureHelpState::default(),
 2095            auto_signature_help: None,
 2096            find_all_references_task_sources: Vec::new(),
 2097            next_completion_id: 0,
 2098            next_inlay_id: 0,
 2099            code_action_providers,
 2100            available_code_actions: None,
 2101            code_actions_task: None,
 2102            quick_selection_highlight_task: None,
 2103            debounced_selection_highlight_task: None,
 2104            document_highlights_task: None,
 2105            linked_editing_range_task: None,
 2106            pending_rename: None,
 2107            searchable: !is_minimap,
 2108            cursor_shape: EditorSettings::get_global(cx)
 2109                .cursor_shape
 2110                .unwrap_or_default(),
 2111            current_line_highlight: None,
 2112            autoindent_mode: Some(AutoindentMode::EachLine),
 2113            collapse_matches: false,
 2114            workspace: None,
 2115            input_enabled: !is_minimap,
 2116            use_modal_editing: full_mode,
 2117            read_only: is_minimap,
 2118            use_autoclose: true,
 2119            use_auto_surround: true,
 2120            auto_replace_emoji_shortcode: false,
 2121            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2122            leader_id: None,
 2123            remote_id: None,
 2124            hover_state: HoverState::default(),
 2125            pending_mouse_down: None,
 2126            hovered_link_state: None,
 2127            edit_prediction_provider: None,
 2128            active_edit_prediction: None,
 2129            stale_edit_prediction_in_menu: None,
 2130            edit_prediction_preview: EditPredictionPreview::Inactive {
 2131                released_too_fast: false,
 2132            },
 2133            inline_diagnostics_enabled: full_mode,
 2134            diagnostics_enabled: full_mode,
 2135            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2136            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2137            gutter_hovered: false,
 2138            pixel_position_of_newest_cursor: None,
 2139            last_bounds: None,
 2140            last_position_map: None,
 2141            expect_bounds_change: None,
 2142            gutter_dimensions: GutterDimensions::default(),
 2143            style: None,
 2144            show_cursor_names: false,
 2145            hovered_cursors: HashMap::default(),
 2146            next_editor_action_id: EditorActionId::default(),
 2147            editor_actions: Rc::default(),
 2148            edit_predictions_hidden_for_vim_mode: false,
 2149            show_edit_predictions_override: None,
 2150            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2151            edit_prediction_settings: EditPredictionSettings::Disabled,
 2152            edit_prediction_indent_conflict: false,
 2153            edit_prediction_requires_modifier_in_indent_conflict: true,
 2154            custom_context_menu: None,
 2155            show_git_blame_gutter: false,
 2156            show_git_blame_inline: false,
 2157            show_selection_menu: None,
 2158            show_git_blame_inline_delay_task: None,
 2159            git_blame_inline_enabled: full_mode
 2160                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2161            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2162            serialize_dirty_buffers: !is_minimap
 2163                && ProjectSettings::get_global(cx)
 2164                    .session
 2165                    .restore_unsaved_buffers,
 2166            blame: None,
 2167            blame_subscription: None,
 2168            tasks: BTreeMap::default(),
 2169
 2170            breakpoint_store,
 2171            gutter_breakpoint_indicator: (None, None),
 2172            hovered_diff_hunk_row: None,
 2173            _subscriptions: (!is_minimap)
 2174                .then(|| {
 2175                    vec![
 2176                        cx.observe(&buffer, Self::on_buffer_changed),
 2177                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2178                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2179                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2180                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2181                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2182                        cx.observe_window_activation(window, |editor, window, cx| {
 2183                            let active = window.is_window_active();
 2184                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2185                                if active {
 2186                                    blink_manager.enable(cx);
 2187                                } else {
 2188                                    blink_manager.disable(cx);
 2189                                }
 2190                            });
 2191                            if active {
 2192                                editor.show_mouse_cursor(cx);
 2193                            }
 2194                        }),
 2195                    ]
 2196                })
 2197                .unwrap_or_default(),
 2198            tasks_update_task: None,
 2199            pull_diagnostics_task: Task::ready(()),
 2200            colors: None,
 2201            next_color_inlay_id: 0,
 2202            linked_edit_ranges: Default::default(),
 2203            in_project_search: false,
 2204            previous_search_ranges: None,
 2205            breadcrumb_header: None,
 2206            focused_block: None,
 2207            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2208            addons: HashMap::default(),
 2209            registered_buffers: HashMap::default(),
 2210            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2211            selection_mark_mode: false,
 2212            toggle_fold_multiple_buffers: Task::ready(()),
 2213            serialize_selections: Task::ready(()),
 2214            serialize_folds: Task::ready(()),
 2215            text_style_refinement: None,
 2216            load_diff_task: load_uncommitted_diff,
 2217            temporary_diff_override: false,
 2218            mouse_cursor_hidden: false,
 2219            minimap: None,
 2220            hide_mouse_mode: EditorSettings::get_global(cx)
 2221                .hide_mouse
 2222                .unwrap_or_default(),
 2223            change_list: ChangeList::new(),
 2224            mode,
 2225            selection_drag_state: SelectionDragState::None,
 2226            folding_newlines: Task::ready(()),
 2227        };
 2228
 2229        if is_minimap {
 2230            return editor;
 2231        }
 2232
 2233        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2234            editor
 2235                ._subscriptions
 2236                .push(cx.observe(breakpoints, |_, _, cx| {
 2237                    cx.notify();
 2238                }));
 2239        }
 2240        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2241        editor._subscriptions.extend(project_subscriptions);
 2242
 2243        editor._subscriptions.push(cx.subscribe_in(
 2244            &cx.entity(),
 2245            window,
 2246            |editor, _, e: &EditorEvent, window, cx| match e {
 2247                EditorEvent::ScrollPositionChanged { local, .. } => {
 2248                    if *local {
 2249                        let new_anchor = editor.scroll_manager.anchor();
 2250                        let snapshot = editor.snapshot(window, cx);
 2251                        editor.update_restoration_data(cx, move |data| {
 2252                            data.scroll_position = (
 2253                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2254                                new_anchor.offset,
 2255                            );
 2256                        });
 2257                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2258                        editor.inline_blame_popover.take();
 2259                    }
 2260                }
 2261                EditorEvent::Edited { .. } => {
 2262                    if !vim_enabled(cx) {
 2263                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2264                        let pop_state = editor
 2265                            .change_list
 2266                            .last()
 2267                            .map(|previous| {
 2268                                previous.len() == selections.len()
 2269                                    && previous.iter().enumerate().all(|(ix, p)| {
 2270                                        p.to_display_point(&map).row()
 2271                                            == selections[ix].head().row()
 2272                                    })
 2273                            })
 2274                            .unwrap_or(false);
 2275                        let new_positions = selections
 2276                            .into_iter()
 2277                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2278                            .collect();
 2279                        editor
 2280                            .change_list
 2281                            .push_to_change_list(pop_state, new_positions);
 2282                    }
 2283                }
 2284                _ => (),
 2285            },
 2286        ));
 2287
 2288        if let Some(dap_store) = editor
 2289            .project
 2290            .as_ref()
 2291            .map(|project| project.read(cx).dap_store())
 2292        {
 2293            let weak_editor = cx.weak_entity();
 2294
 2295            editor
 2296                ._subscriptions
 2297                .push(
 2298                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2299                        let session_entity = cx.entity();
 2300                        weak_editor
 2301                            .update(cx, |editor, cx| {
 2302                                editor._subscriptions.push(
 2303                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2304                                );
 2305                            })
 2306                            .ok();
 2307                    }),
 2308                );
 2309
 2310            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2311                editor
 2312                    ._subscriptions
 2313                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2314            }
 2315        }
 2316
 2317        // skip adding the initial selection to selection history
 2318        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2319        editor.end_selection(window, cx);
 2320        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2321
 2322        editor.scroll_manager.show_scrollbars(window, cx);
 2323        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2324
 2325        if full_mode {
 2326            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2327            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2328
 2329            if editor.git_blame_inline_enabled {
 2330                editor.start_git_blame_inline(false, window, cx);
 2331            }
 2332
 2333            editor.go_to_active_debug_line(window, cx);
 2334
 2335            if let Some(buffer) = buffer.read(cx).as_singleton()
 2336                && let Some(project) = editor.project()
 2337            {
 2338                let handle = project.update(cx, |project, cx| {
 2339                    project.register_buffer_with_language_servers(&buffer, cx)
 2340                });
 2341                editor
 2342                    .registered_buffers
 2343                    .insert(buffer.read(cx).remote_id(), handle);
 2344            }
 2345
 2346            editor.minimap =
 2347                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2348            editor.colors = Some(LspColorData::new(cx));
 2349            editor.update_lsp_data(false, None, window, cx);
 2350        }
 2351
 2352        if editor.mode.is_full() {
 2353            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2354        }
 2355
 2356        editor
 2357    }
 2358
 2359    pub fn deploy_mouse_context_menu(
 2360        &mut self,
 2361        position: gpui::Point<Pixels>,
 2362        context_menu: Entity<ContextMenu>,
 2363        window: &mut Window,
 2364        cx: &mut Context<Self>,
 2365    ) {
 2366        self.mouse_context_menu = Some(MouseContextMenu::new(
 2367            self,
 2368            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2369            context_menu,
 2370            window,
 2371            cx,
 2372        ));
 2373    }
 2374
 2375    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2376        self.mouse_context_menu
 2377            .as_ref()
 2378            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2379    }
 2380
 2381    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2382        if self
 2383            .selections
 2384            .pending
 2385            .as_ref()
 2386            .is_some_and(|pending_selection| {
 2387                let snapshot = self.buffer().read(cx).snapshot(cx);
 2388                pending_selection
 2389                    .selection
 2390                    .range()
 2391                    .includes(range, &snapshot)
 2392            })
 2393        {
 2394            return true;
 2395        }
 2396
 2397        self.selections
 2398            .disjoint_in_range::<usize>(range.clone(), cx)
 2399            .into_iter()
 2400            .any(|selection| {
 2401                // This is needed to cover a corner case, if we just check for an existing
 2402                // selection in the fold range, having a cursor at the start of the fold
 2403                // marks it as selected. Non-empty selections don't cause this.
 2404                let length = selection.end - selection.start;
 2405                length > 0
 2406            })
 2407    }
 2408
 2409    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2410        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2411    }
 2412
 2413    fn key_context_internal(
 2414        &self,
 2415        has_active_edit_prediction: bool,
 2416        window: &Window,
 2417        cx: &App,
 2418    ) -> KeyContext {
 2419        let mut key_context = KeyContext::new_with_defaults();
 2420        key_context.add("Editor");
 2421        let mode = match self.mode {
 2422            EditorMode::SingleLine { .. } => "single_line",
 2423            EditorMode::AutoHeight { .. } => "auto_height",
 2424            EditorMode::Minimap { .. } => "minimap",
 2425            EditorMode::Full { .. } => "full",
 2426        };
 2427
 2428        if EditorSettings::jupyter_enabled(cx) {
 2429            key_context.add("jupyter");
 2430        }
 2431
 2432        key_context.set("mode", mode);
 2433        if self.pending_rename.is_some() {
 2434            key_context.add("renaming");
 2435        }
 2436
 2437        match self.context_menu.borrow().as_ref() {
 2438            Some(CodeContextMenu::Completions(menu)) => {
 2439                if menu.visible() {
 2440                    key_context.add("menu");
 2441                    key_context.add("showing_completions");
 2442                }
 2443            }
 2444            Some(CodeContextMenu::CodeActions(menu)) => {
 2445                if menu.visible() {
 2446                    key_context.add("menu");
 2447                    key_context.add("showing_code_actions")
 2448                }
 2449            }
 2450            None => {}
 2451        }
 2452
 2453        if self.signature_help_state.has_multiple_signatures() {
 2454            key_context.add("showing_signature_help");
 2455        }
 2456
 2457        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2458        if !self.focus_handle(cx).contains_focused(window, cx)
 2459            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2460        {
 2461            for addon in self.addons.values() {
 2462                addon.extend_key_context(&mut key_context, cx)
 2463            }
 2464        }
 2465
 2466        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2467            if let Some(extension) = singleton_buffer
 2468                .read(cx)
 2469                .file()
 2470                .and_then(|file| file.path().extension()?.to_str())
 2471            {
 2472                key_context.set("extension", extension.to_string());
 2473            }
 2474        } else {
 2475            key_context.add("multibuffer");
 2476        }
 2477
 2478        if has_active_edit_prediction {
 2479            if self.edit_prediction_in_conflict() {
 2480                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2481            } else {
 2482                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2483                key_context.add("copilot_suggestion");
 2484            }
 2485        }
 2486
 2487        if self.selection_mark_mode {
 2488            key_context.add("selection_mode");
 2489        }
 2490
 2491        key_context
 2492    }
 2493
 2494    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2495        if self.mouse_cursor_hidden {
 2496            self.mouse_cursor_hidden = false;
 2497            cx.notify();
 2498        }
 2499    }
 2500
 2501    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2502        let hide_mouse_cursor = match origin {
 2503            HideMouseCursorOrigin::TypingAction => {
 2504                matches!(
 2505                    self.hide_mouse_mode,
 2506                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2507                )
 2508            }
 2509            HideMouseCursorOrigin::MovementAction => {
 2510                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2511            }
 2512        };
 2513        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2514            self.mouse_cursor_hidden = hide_mouse_cursor;
 2515            cx.notify();
 2516        }
 2517    }
 2518
 2519    pub fn edit_prediction_in_conflict(&self) -> bool {
 2520        if !self.show_edit_predictions_in_menu() {
 2521            return false;
 2522        }
 2523
 2524        let showing_completions = self
 2525            .context_menu
 2526            .borrow()
 2527            .as_ref()
 2528            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2529
 2530        showing_completions
 2531            || self.edit_prediction_requires_modifier()
 2532            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2533            // bindings to insert tab characters.
 2534            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2535    }
 2536
 2537    pub fn accept_edit_prediction_keybind(
 2538        &self,
 2539        accept_partial: bool,
 2540        window: &Window,
 2541        cx: &App,
 2542    ) -> AcceptEditPredictionBinding {
 2543        let key_context = self.key_context_internal(true, window, cx);
 2544        let in_conflict = self.edit_prediction_in_conflict();
 2545
 2546        let bindings = if accept_partial {
 2547            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2548        } else {
 2549            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2550        };
 2551
 2552        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2553        // just the first one.
 2554        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2555            !in_conflict
 2556                || binding
 2557                    .keystrokes()
 2558                    .first()
 2559                    .is_some_and(|keystroke| keystroke.modifiers.modified())
 2560        }))
 2561    }
 2562
 2563    pub fn new_file(
 2564        workspace: &mut Workspace,
 2565        _: &workspace::NewFile,
 2566        window: &mut Window,
 2567        cx: &mut Context<Workspace>,
 2568    ) {
 2569        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2570            "Failed to create buffer",
 2571            window,
 2572            cx,
 2573            |e, _, _| match e.error_code() {
 2574                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2575                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2576                e.error_tag("required").unwrap_or("the latest version")
 2577            )),
 2578                _ => None,
 2579            },
 2580        );
 2581    }
 2582
 2583    pub fn new_in_workspace(
 2584        workspace: &mut Workspace,
 2585        window: &mut Window,
 2586        cx: &mut Context<Workspace>,
 2587    ) -> Task<Result<Entity<Editor>>> {
 2588        let project = workspace.project().clone();
 2589        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2590
 2591        cx.spawn_in(window, async move |workspace, cx| {
 2592            let buffer = create.await?;
 2593            workspace.update_in(cx, |workspace, window, cx| {
 2594                let editor =
 2595                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2596                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2597                editor
 2598            })
 2599        })
 2600    }
 2601
 2602    fn new_file_vertical(
 2603        workspace: &mut Workspace,
 2604        _: &workspace::NewFileSplitVertical,
 2605        window: &mut Window,
 2606        cx: &mut Context<Workspace>,
 2607    ) {
 2608        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2609    }
 2610
 2611    fn new_file_horizontal(
 2612        workspace: &mut Workspace,
 2613        _: &workspace::NewFileSplitHorizontal,
 2614        window: &mut Window,
 2615        cx: &mut Context<Workspace>,
 2616    ) {
 2617        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2618    }
 2619
 2620    fn new_file_in_direction(
 2621        workspace: &mut Workspace,
 2622        direction: SplitDirection,
 2623        window: &mut Window,
 2624        cx: &mut Context<Workspace>,
 2625    ) {
 2626        let project = workspace.project().clone();
 2627        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2628
 2629        cx.spawn_in(window, async move |workspace, cx| {
 2630            let buffer = create.await?;
 2631            workspace.update_in(cx, move |workspace, window, cx| {
 2632                workspace.split_item(
 2633                    direction,
 2634                    Box::new(
 2635                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2636                    ),
 2637                    window,
 2638                    cx,
 2639                )
 2640            })?;
 2641            anyhow::Ok(())
 2642        })
 2643        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2644            match e.error_code() {
 2645                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2646                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2647                e.error_tag("required").unwrap_or("the latest version")
 2648            )),
 2649                _ => None,
 2650            }
 2651        });
 2652    }
 2653
 2654    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2655        self.leader_id
 2656    }
 2657
 2658    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2659        &self.buffer
 2660    }
 2661
 2662    pub fn project(&self) -> Option<&Entity<Project>> {
 2663        self.project.as_ref()
 2664    }
 2665
 2666    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2667        self.workspace.as_ref()?.0.upgrade()
 2668    }
 2669
 2670    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2671        self.buffer().read(cx).title(cx)
 2672    }
 2673
 2674    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2675        let git_blame_gutter_max_author_length = self
 2676            .render_git_blame_gutter(cx)
 2677            .then(|| {
 2678                if let Some(blame) = self.blame.as_ref() {
 2679                    let max_author_length =
 2680                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2681                    Some(max_author_length)
 2682                } else {
 2683                    None
 2684                }
 2685            })
 2686            .flatten();
 2687
 2688        EditorSnapshot {
 2689            mode: self.mode.clone(),
 2690            show_gutter: self.show_gutter,
 2691            show_line_numbers: self.show_line_numbers,
 2692            show_git_diff_gutter: self.show_git_diff_gutter,
 2693            show_code_actions: self.show_code_actions,
 2694            show_runnables: self.show_runnables,
 2695            show_breakpoints: self.show_breakpoints,
 2696            git_blame_gutter_max_author_length,
 2697            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2698            scroll_anchor: self.scroll_manager.anchor(),
 2699            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2700            placeholder_text: self.placeholder_text.clone(),
 2701            is_focused: self.focus_handle.is_focused(window),
 2702            current_line_highlight: self
 2703                .current_line_highlight
 2704                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2705            gutter_hovered: self.gutter_hovered,
 2706        }
 2707    }
 2708
 2709    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2710        self.buffer.read(cx).language_at(point, cx)
 2711    }
 2712
 2713    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2714        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2715    }
 2716
 2717    pub fn active_excerpt(
 2718        &self,
 2719        cx: &App,
 2720    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2721        self.buffer
 2722            .read(cx)
 2723            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2724    }
 2725
 2726    pub fn mode(&self) -> &EditorMode {
 2727        &self.mode
 2728    }
 2729
 2730    pub fn set_mode(&mut self, mode: EditorMode) {
 2731        self.mode = mode;
 2732    }
 2733
 2734    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2735        self.collaboration_hub.as_deref()
 2736    }
 2737
 2738    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2739        self.collaboration_hub = Some(hub);
 2740    }
 2741
 2742    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2743        self.in_project_search = in_project_search;
 2744    }
 2745
 2746    pub fn set_custom_context_menu(
 2747        &mut self,
 2748        f: impl 'static
 2749        + Fn(
 2750            &mut Self,
 2751            DisplayPoint,
 2752            &mut Window,
 2753            &mut Context<Self>,
 2754        ) -> Option<Entity<ui::ContextMenu>>,
 2755    ) {
 2756        self.custom_context_menu = Some(Box::new(f))
 2757    }
 2758
 2759    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2760        self.completion_provider = provider;
 2761    }
 2762
 2763    #[cfg(any(test, feature = "test-support"))]
 2764    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2765        self.completion_provider.clone()
 2766    }
 2767
 2768    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2769        self.semantics_provider.clone()
 2770    }
 2771
 2772    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2773        self.semantics_provider = provider;
 2774    }
 2775
 2776    pub fn set_edit_prediction_provider<T>(
 2777        &mut self,
 2778        provider: Option<Entity<T>>,
 2779        window: &mut Window,
 2780        cx: &mut Context<Self>,
 2781    ) where
 2782        T: EditPredictionProvider,
 2783    {
 2784        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2785            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2786                if this.focus_handle.is_focused(window) {
 2787                    this.update_visible_edit_prediction(window, cx);
 2788                }
 2789            }),
 2790            provider: Arc::new(provider),
 2791        });
 2792        self.update_edit_prediction_settings(cx);
 2793        self.refresh_edit_prediction(false, false, window, cx);
 2794    }
 2795
 2796    pub fn placeholder_text(&self) -> Option<&str> {
 2797        self.placeholder_text.as_deref()
 2798    }
 2799
 2800    pub fn set_placeholder_text(
 2801        &mut self,
 2802        placeholder_text: impl Into<Arc<str>>,
 2803        cx: &mut Context<Self>,
 2804    ) {
 2805        let placeholder_text = Some(placeholder_text.into());
 2806        if self.placeholder_text != placeholder_text {
 2807            self.placeholder_text = placeholder_text;
 2808            cx.notify();
 2809        }
 2810    }
 2811
 2812    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2813        self.cursor_shape = cursor_shape;
 2814
 2815        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2816        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2817
 2818        cx.notify();
 2819    }
 2820
 2821    pub fn set_current_line_highlight(
 2822        &mut self,
 2823        current_line_highlight: Option<CurrentLineHighlight>,
 2824    ) {
 2825        self.current_line_highlight = current_line_highlight;
 2826    }
 2827
 2828    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2829        self.collapse_matches = collapse_matches;
 2830    }
 2831
 2832    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2833        let buffers = self.buffer.read(cx).all_buffers();
 2834        let Some(project) = self.project.as_ref() else {
 2835            return;
 2836        };
 2837        project.update(cx, |project, cx| {
 2838            for buffer in buffers {
 2839                self.registered_buffers
 2840                    .entry(buffer.read(cx).remote_id())
 2841                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2842            }
 2843        })
 2844    }
 2845
 2846    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2847        if self.collapse_matches {
 2848            return range.start..range.start;
 2849        }
 2850        range.clone()
 2851    }
 2852
 2853    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2854        if self.display_map.read(cx).clip_at_line_ends != clip {
 2855            self.display_map
 2856                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2857        }
 2858    }
 2859
 2860    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2861        self.input_enabled = input_enabled;
 2862    }
 2863
 2864    pub fn set_edit_predictions_hidden_for_vim_mode(
 2865        &mut self,
 2866        hidden: bool,
 2867        window: &mut Window,
 2868        cx: &mut Context<Self>,
 2869    ) {
 2870        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2871            self.edit_predictions_hidden_for_vim_mode = hidden;
 2872            if hidden {
 2873                self.update_visible_edit_prediction(window, cx);
 2874            } else {
 2875                self.refresh_edit_prediction(true, false, window, cx);
 2876            }
 2877        }
 2878    }
 2879
 2880    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2881        self.menu_edit_predictions_policy = value;
 2882    }
 2883
 2884    pub fn set_autoindent(&mut self, autoindent: bool) {
 2885        if autoindent {
 2886            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2887        } else {
 2888            self.autoindent_mode = None;
 2889        }
 2890    }
 2891
 2892    pub fn read_only(&self, cx: &App) -> bool {
 2893        self.read_only || self.buffer.read(cx).read_only()
 2894    }
 2895
 2896    pub fn set_read_only(&mut self, read_only: bool) {
 2897        self.read_only = read_only;
 2898    }
 2899
 2900    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2901        self.use_autoclose = autoclose;
 2902    }
 2903
 2904    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2905        self.use_auto_surround = auto_surround;
 2906    }
 2907
 2908    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2909        self.auto_replace_emoji_shortcode = auto_replace;
 2910    }
 2911
 2912    pub fn toggle_edit_predictions(
 2913        &mut self,
 2914        _: &ToggleEditPrediction,
 2915        window: &mut Window,
 2916        cx: &mut Context<Self>,
 2917    ) {
 2918        if self.show_edit_predictions_override.is_some() {
 2919            self.set_show_edit_predictions(None, window, cx);
 2920        } else {
 2921            let show_edit_predictions = !self.edit_predictions_enabled();
 2922            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2923        }
 2924    }
 2925
 2926    pub fn set_show_edit_predictions(
 2927        &mut self,
 2928        show_edit_predictions: Option<bool>,
 2929        window: &mut Window,
 2930        cx: &mut Context<Self>,
 2931    ) {
 2932        self.show_edit_predictions_override = show_edit_predictions;
 2933        self.update_edit_prediction_settings(cx);
 2934
 2935        if let Some(false) = show_edit_predictions {
 2936            self.discard_edit_prediction(false, cx);
 2937        } else {
 2938            self.refresh_edit_prediction(false, true, window, cx);
 2939        }
 2940    }
 2941
 2942    fn edit_predictions_disabled_in_scope(
 2943        &self,
 2944        buffer: &Entity<Buffer>,
 2945        buffer_position: language::Anchor,
 2946        cx: &App,
 2947    ) -> bool {
 2948        let snapshot = buffer.read(cx).snapshot();
 2949        let settings = snapshot.settings_at(buffer_position, cx);
 2950
 2951        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2952            return false;
 2953        };
 2954
 2955        scope.override_name().is_some_and(|scope_name| {
 2956            settings
 2957                .edit_predictions_disabled_in
 2958                .iter()
 2959                .any(|s| s == scope_name)
 2960        })
 2961    }
 2962
 2963    pub fn set_use_modal_editing(&mut self, to: bool) {
 2964        self.use_modal_editing = to;
 2965    }
 2966
 2967    pub fn use_modal_editing(&self) -> bool {
 2968        self.use_modal_editing
 2969    }
 2970
 2971    fn selections_did_change(
 2972        &mut self,
 2973        local: bool,
 2974        old_cursor_position: &Anchor,
 2975        effects: SelectionEffects,
 2976        window: &mut Window,
 2977        cx: &mut Context<Self>,
 2978    ) {
 2979        window.invalidate_character_coordinates();
 2980
 2981        // Copy selections to primary selection buffer
 2982        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2983        if local {
 2984            let selections = self.selections.all::<usize>(cx);
 2985            let buffer_handle = self.buffer.read(cx).read(cx);
 2986
 2987            let mut text = String::new();
 2988            for (index, selection) in selections.iter().enumerate() {
 2989                let text_for_selection = buffer_handle
 2990                    .text_for_range(selection.start..selection.end)
 2991                    .collect::<String>();
 2992
 2993                text.push_str(&text_for_selection);
 2994                if index != selections.len() - 1 {
 2995                    text.push('\n');
 2996                }
 2997            }
 2998
 2999            if !text.is_empty() {
 3000                cx.write_to_primary(ClipboardItem::new_string(text));
 3001            }
 3002        }
 3003
 3004        let selection_anchors = self.selections.disjoint_anchors();
 3005
 3006        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3007            self.buffer.update(cx, |buffer, cx| {
 3008                buffer.set_active_selections(
 3009                    &selection_anchors,
 3010                    self.selections.line_mode,
 3011                    self.cursor_shape,
 3012                    cx,
 3013                )
 3014            });
 3015        }
 3016        let display_map = self
 3017            .display_map
 3018            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3019        let buffer = &display_map.buffer_snapshot;
 3020        if self.selections.count() == 1 {
 3021            self.add_selections_state = None;
 3022        }
 3023        self.select_next_state = None;
 3024        self.select_prev_state = None;
 3025        self.select_syntax_node_history.try_clear();
 3026        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3027        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3028        self.take_rename(false, window, cx);
 3029
 3030        let newest_selection = self.selections.newest_anchor();
 3031        let new_cursor_position = newest_selection.head();
 3032        let selection_start = newest_selection.start;
 3033
 3034        let new_cursor_point = new_cursor_position.to_point(buffer);
 3035        if let Some(project) = self.project()
 3036            && let Some((path, worktree_path)) =
 3037                self.file_at(new_cursor_point, cx).and_then(|file| {
 3038                    file.as_local().and_then(|file| {
 3039                        let worktree =
 3040                            project.read(cx).worktree_for_id(file.worktree_id(cx), cx)?;
 3041                        Some((file.abs_path(cx), worktree.read(cx).abs_path()))
 3042                    })
 3043                })
 3044        {
 3045            *LAST_CURSOR_POSITION_WATCH.0.lock().borrow_mut() = Some(LastCursorPosition {
 3046                path,
 3047                worktree_path,
 3048                point: new_cursor_point,
 3049            });
 3050        }
 3051
 3052        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3053            self.push_to_nav_history(
 3054                *old_cursor_position,
 3055                Some(new_cursor_point),
 3056                false,
 3057                effects.nav_history == Some(true),
 3058                cx,
 3059            );
 3060        }
 3061
 3062        if local {
 3063            if let Some(buffer_id) = new_cursor_position.buffer_id
 3064                && !self.registered_buffers.contains_key(&buffer_id)
 3065                && let Some(project) = self.project.as_ref()
 3066            {
 3067                project.update(cx, |project, cx| {
 3068                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3069                        return;
 3070                    };
 3071                    self.registered_buffers.insert(
 3072                        buffer_id,
 3073                        project.register_buffer_with_language_servers(&buffer, cx),
 3074                    );
 3075                })
 3076            }
 3077
 3078            let mut context_menu = self.context_menu.borrow_mut();
 3079            let completion_menu = match context_menu.as_ref() {
 3080                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3081                Some(CodeContextMenu::CodeActions(_)) => {
 3082                    *context_menu = None;
 3083                    None
 3084                }
 3085                None => None,
 3086            };
 3087            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3088            drop(context_menu);
 3089
 3090            if effects.completions
 3091                && let Some(completion_position) = completion_position
 3092            {
 3093                let start_offset = selection_start.to_offset(buffer);
 3094                let position_matches = start_offset == completion_position.to_offset(buffer);
 3095                let continue_showing = if position_matches {
 3096                    if self.snippet_stack.is_empty() {
 3097                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3098                    } else {
 3099                        // Snippet choices can be shown even when the cursor is in whitespace.
 3100                        // Dismissing the menu with actions like backspace is handled by
 3101                        // invalidation regions.
 3102                        true
 3103                    }
 3104                } else {
 3105                    false
 3106                };
 3107
 3108                if continue_showing {
 3109                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3110                } else {
 3111                    self.hide_context_menu(window, cx);
 3112                }
 3113            }
 3114
 3115            hide_hover(self, cx);
 3116
 3117            if old_cursor_position.to_display_point(&display_map).row()
 3118                != new_cursor_position.to_display_point(&display_map).row()
 3119            {
 3120                self.available_code_actions.take();
 3121            }
 3122            self.refresh_code_actions(window, cx);
 3123            self.refresh_document_highlights(cx);
 3124            self.refresh_selected_text_highlights(false, window, cx);
 3125            refresh_matching_bracket_highlights(self, window, cx);
 3126            self.update_visible_edit_prediction(window, cx);
 3127            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3128            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3129            self.inline_blame_popover.take();
 3130            if self.git_blame_inline_enabled {
 3131                self.start_inline_blame_timer(window, cx);
 3132            }
 3133        }
 3134
 3135        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3136        cx.emit(EditorEvent::SelectionsChanged { local });
 3137
 3138        let selections = &self.selections.disjoint;
 3139        if selections.len() == 1 {
 3140            cx.emit(SearchEvent::ActiveMatchChanged)
 3141        }
 3142        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3143            let inmemory_selections = selections
 3144                .iter()
 3145                .map(|s| {
 3146                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3147                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3148                })
 3149                .collect();
 3150            self.update_restoration_data(cx, |data| {
 3151                data.selections = inmemory_selections;
 3152            });
 3153
 3154            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3155                && let Some(workspace_id) =
 3156                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3157            {
 3158                let snapshot = self.buffer().read(cx).snapshot(cx);
 3159                let selections = selections.clone();
 3160                let background_executor = cx.background_executor().clone();
 3161                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3162                self.serialize_selections = cx.background_spawn(async move {
 3163                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3164                            let db_selections = selections
 3165                                .iter()
 3166                                .map(|selection| {
 3167                                    (
 3168                                        selection.start.to_offset(&snapshot),
 3169                                        selection.end.to_offset(&snapshot),
 3170                                    )
 3171                                })
 3172                                .collect();
 3173
 3174                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3175                                .await
 3176                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3177                                .log_err();
 3178                        });
 3179            }
 3180        }
 3181
 3182        cx.notify();
 3183    }
 3184
 3185    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3186        use text::ToOffset as _;
 3187        use text::ToPoint as _;
 3188
 3189        if self.mode.is_minimap()
 3190            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3191        {
 3192            return;
 3193        }
 3194
 3195        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3196            return;
 3197        };
 3198
 3199        let snapshot = singleton.read(cx).snapshot();
 3200        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3201            let display_snapshot = display_map.snapshot(cx);
 3202
 3203            display_snapshot
 3204                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3205                .map(|fold| {
 3206                    fold.range.start.text_anchor.to_point(&snapshot)
 3207                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3208                })
 3209                .collect()
 3210        });
 3211        self.update_restoration_data(cx, |data| {
 3212            data.folds = inmemory_folds;
 3213        });
 3214
 3215        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3216            return;
 3217        };
 3218        let background_executor = cx.background_executor().clone();
 3219        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3220        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3221            display_map
 3222                .snapshot(cx)
 3223                .folds_in_range(0..snapshot.len())
 3224                .map(|fold| {
 3225                    (
 3226                        fold.range.start.text_anchor.to_offset(&snapshot),
 3227                        fold.range.end.text_anchor.to_offset(&snapshot),
 3228                    )
 3229                })
 3230                .collect()
 3231        });
 3232        self.serialize_folds = cx.background_spawn(async move {
 3233            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3234            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3235                .await
 3236                .with_context(|| {
 3237                    format!(
 3238                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3239                    )
 3240                })
 3241                .log_err();
 3242        });
 3243    }
 3244
 3245    pub fn sync_selections(
 3246        &mut self,
 3247        other: Entity<Editor>,
 3248        cx: &mut Context<Self>,
 3249    ) -> gpui::Subscription {
 3250        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3251        self.selections.change_with(cx, |selections| {
 3252            selections.select_anchors(other_selections);
 3253        });
 3254
 3255        let other_subscription =
 3256            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3257                EditorEvent::SelectionsChanged { local: true } => {
 3258                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3259                    if other_selections.is_empty() {
 3260                        return;
 3261                    }
 3262                    this.selections.change_with(cx, |selections| {
 3263                        selections.select_anchors(other_selections);
 3264                    });
 3265                }
 3266                _ => {}
 3267            });
 3268
 3269        let this_subscription =
 3270            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3271                EditorEvent::SelectionsChanged { local: true } => {
 3272                    let these_selections = this.selections.disjoint.to_vec();
 3273                    if these_selections.is_empty() {
 3274                        return;
 3275                    }
 3276                    other.update(cx, |other_editor, cx| {
 3277                        other_editor.selections.change_with(cx, |selections| {
 3278                            selections.select_anchors(these_selections);
 3279                        })
 3280                    });
 3281                }
 3282                _ => {}
 3283            });
 3284
 3285        Subscription::join(other_subscription, this_subscription)
 3286    }
 3287
 3288    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3289    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3290    /// effects of selection change occur at the end of the transaction.
 3291    pub fn change_selections<R>(
 3292        &mut self,
 3293        effects: SelectionEffects,
 3294        window: &mut Window,
 3295        cx: &mut Context<Self>,
 3296        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3297    ) -> R {
 3298        if let Some(state) = &mut self.deferred_selection_effects_state {
 3299            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3300            state.effects.completions = effects.completions;
 3301            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3302            let (changed, result) = self.selections.change_with(cx, change);
 3303            state.changed |= changed;
 3304            return result;
 3305        }
 3306        let mut state = DeferredSelectionEffectsState {
 3307            changed: false,
 3308            effects,
 3309            old_cursor_position: self.selections.newest_anchor().head(),
 3310            history_entry: SelectionHistoryEntry {
 3311                selections: self.selections.disjoint_anchors(),
 3312                select_next_state: self.select_next_state.clone(),
 3313                select_prev_state: self.select_prev_state.clone(),
 3314                add_selections_state: self.add_selections_state.clone(),
 3315            },
 3316        };
 3317        let (changed, result) = self.selections.change_with(cx, change);
 3318        state.changed = state.changed || changed;
 3319        if self.defer_selection_effects {
 3320            self.deferred_selection_effects_state = Some(state);
 3321        } else {
 3322            self.apply_selection_effects(state, window, cx);
 3323        }
 3324        result
 3325    }
 3326
 3327    /// Defers the effects of selection change, so that the effects of multiple calls to
 3328    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3329    /// to selection history and the state of popovers based on selection position aren't
 3330    /// erroneously updated.
 3331    pub fn with_selection_effects_deferred<R>(
 3332        &mut self,
 3333        window: &mut Window,
 3334        cx: &mut Context<Self>,
 3335        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3336    ) -> R {
 3337        let already_deferred = self.defer_selection_effects;
 3338        self.defer_selection_effects = true;
 3339        let result = update(self, window, cx);
 3340        if !already_deferred {
 3341            self.defer_selection_effects = false;
 3342            if let Some(state) = self.deferred_selection_effects_state.take() {
 3343                self.apply_selection_effects(state, window, cx);
 3344            }
 3345        }
 3346        result
 3347    }
 3348
 3349    fn apply_selection_effects(
 3350        &mut self,
 3351        state: DeferredSelectionEffectsState,
 3352        window: &mut Window,
 3353        cx: &mut Context<Self>,
 3354    ) {
 3355        if state.changed {
 3356            self.selection_history.push(state.history_entry);
 3357
 3358            if let Some(autoscroll) = state.effects.scroll {
 3359                self.request_autoscroll(autoscroll, cx);
 3360            }
 3361
 3362            let old_cursor_position = &state.old_cursor_position;
 3363
 3364            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3365
 3366            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3367                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3368            }
 3369        }
 3370    }
 3371
 3372    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3373    where
 3374        I: IntoIterator<Item = (Range<S>, T)>,
 3375        S: ToOffset,
 3376        T: Into<Arc<str>>,
 3377    {
 3378        if self.read_only(cx) {
 3379            return;
 3380        }
 3381
 3382        self.buffer
 3383            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3384    }
 3385
 3386    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3387    where
 3388        I: IntoIterator<Item = (Range<S>, T)>,
 3389        S: ToOffset,
 3390        T: Into<Arc<str>>,
 3391    {
 3392        if self.read_only(cx) {
 3393            return;
 3394        }
 3395
 3396        self.buffer.update(cx, |buffer, cx| {
 3397            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3398        });
 3399    }
 3400
 3401    pub fn edit_with_block_indent<I, S, T>(
 3402        &mut self,
 3403        edits: I,
 3404        original_indent_columns: Vec<Option<u32>>,
 3405        cx: &mut Context<Self>,
 3406    ) where
 3407        I: IntoIterator<Item = (Range<S>, T)>,
 3408        S: ToOffset,
 3409        T: Into<Arc<str>>,
 3410    {
 3411        if self.read_only(cx) {
 3412            return;
 3413        }
 3414
 3415        self.buffer.update(cx, |buffer, cx| {
 3416            buffer.edit(
 3417                edits,
 3418                Some(AutoindentMode::Block {
 3419                    original_indent_columns,
 3420                }),
 3421                cx,
 3422            )
 3423        });
 3424    }
 3425
 3426    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3427        self.hide_context_menu(window, cx);
 3428
 3429        match phase {
 3430            SelectPhase::Begin {
 3431                position,
 3432                add,
 3433                click_count,
 3434            } => self.begin_selection(position, add, click_count, window, cx),
 3435            SelectPhase::BeginColumnar {
 3436                position,
 3437                goal_column,
 3438                reset,
 3439                mode,
 3440            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3441            SelectPhase::Extend {
 3442                position,
 3443                click_count,
 3444            } => self.extend_selection(position, click_count, window, cx),
 3445            SelectPhase::Update {
 3446                position,
 3447                goal_column,
 3448                scroll_delta,
 3449            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3450            SelectPhase::End => self.end_selection(window, cx),
 3451        }
 3452    }
 3453
 3454    fn extend_selection(
 3455        &mut self,
 3456        position: DisplayPoint,
 3457        click_count: usize,
 3458        window: &mut Window,
 3459        cx: &mut Context<Self>,
 3460    ) {
 3461        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3462        let tail = self.selections.newest::<usize>(cx).tail();
 3463        self.begin_selection(position, false, click_count, window, cx);
 3464
 3465        let position = position.to_offset(&display_map, Bias::Left);
 3466        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3467
 3468        let mut pending_selection = self
 3469            .selections
 3470            .pending_anchor()
 3471            .expect("extend_selection not called with pending selection");
 3472        if position >= tail {
 3473            pending_selection.start = tail_anchor;
 3474        } else {
 3475            pending_selection.end = tail_anchor;
 3476            pending_selection.reversed = true;
 3477        }
 3478
 3479        let mut pending_mode = self.selections.pending_mode().unwrap();
 3480        match &mut pending_mode {
 3481            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3482            _ => {}
 3483        }
 3484
 3485        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3486            SelectionEffects::scroll(Autoscroll::fit())
 3487        } else {
 3488            SelectionEffects::no_scroll()
 3489        };
 3490
 3491        self.change_selections(effects, window, cx, |s| {
 3492            s.set_pending(pending_selection, pending_mode)
 3493        });
 3494    }
 3495
 3496    fn begin_selection(
 3497        &mut self,
 3498        position: DisplayPoint,
 3499        add: bool,
 3500        click_count: usize,
 3501        window: &mut Window,
 3502        cx: &mut Context<Self>,
 3503    ) {
 3504        if !self.focus_handle.is_focused(window) {
 3505            self.last_focused_descendant = None;
 3506            window.focus(&self.focus_handle);
 3507        }
 3508
 3509        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3510        let buffer = &display_map.buffer_snapshot;
 3511        let position = display_map.clip_point(position, Bias::Left);
 3512
 3513        let start;
 3514        let end;
 3515        let mode;
 3516        let mut auto_scroll;
 3517        match click_count {
 3518            1 => {
 3519                start = buffer.anchor_before(position.to_point(&display_map));
 3520                end = start;
 3521                mode = SelectMode::Character;
 3522                auto_scroll = true;
 3523            }
 3524            2 => {
 3525                let position = display_map
 3526                    .clip_point(position, Bias::Left)
 3527                    .to_offset(&display_map, Bias::Left);
 3528                let (range, _) = buffer.surrounding_word(position, false);
 3529                start = buffer.anchor_before(range.start);
 3530                end = buffer.anchor_before(range.end);
 3531                mode = SelectMode::Word(start..end);
 3532                auto_scroll = true;
 3533            }
 3534            3 => {
 3535                let position = display_map
 3536                    .clip_point(position, Bias::Left)
 3537                    .to_point(&display_map);
 3538                let line_start = display_map.prev_line_boundary(position).0;
 3539                let next_line_start = buffer.clip_point(
 3540                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3541                    Bias::Left,
 3542                );
 3543                start = buffer.anchor_before(line_start);
 3544                end = buffer.anchor_before(next_line_start);
 3545                mode = SelectMode::Line(start..end);
 3546                auto_scroll = true;
 3547            }
 3548            _ => {
 3549                start = buffer.anchor_before(0);
 3550                end = buffer.anchor_before(buffer.len());
 3551                mode = SelectMode::All;
 3552                auto_scroll = false;
 3553            }
 3554        }
 3555        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3556
 3557        let point_to_delete: Option<usize> = {
 3558            let selected_points: Vec<Selection<Point>> =
 3559                self.selections.disjoint_in_range(start..end, cx);
 3560
 3561            if !add || click_count > 1 {
 3562                None
 3563            } else if !selected_points.is_empty() {
 3564                Some(selected_points[0].id)
 3565            } else {
 3566                let clicked_point_already_selected =
 3567                    self.selections.disjoint.iter().find(|selection| {
 3568                        selection.start.to_point(buffer) == start.to_point(buffer)
 3569                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3570                    });
 3571
 3572                clicked_point_already_selected.map(|selection| selection.id)
 3573            }
 3574        };
 3575
 3576        let selections_count = self.selections.count();
 3577        let effects = if auto_scroll {
 3578            SelectionEffects::default()
 3579        } else {
 3580            SelectionEffects::no_scroll()
 3581        };
 3582
 3583        self.change_selections(effects, window, cx, |s| {
 3584            if let Some(point_to_delete) = point_to_delete {
 3585                s.delete(point_to_delete);
 3586
 3587                if selections_count == 1 {
 3588                    s.set_pending_anchor_range(start..end, mode);
 3589                }
 3590            } else {
 3591                if !add {
 3592                    s.clear_disjoint();
 3593                }
 3594
 3595                s.set_pending_anchor_range(start..end, mode);
 3596            }
 3597        });
 3598    }
 3599
 3600    fn begin_columnar_selection(
 3601        &mut self,
 3602        position: DisplayPoint,
 3603        goal_column: u32,
 3604        reset: bool,
 3605        mode: ColumnarMode,
 3606        window: &mut Window,
 3607        cx: &mut Context<Self>,
 3608    ) {
 3609        if !self.focus_handle.is_focused(window) {
 3610            self.last_focused_descendant = None;
 3611            window.focus(&self.focus_handle);
 3612        }
 3613
 3614        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3615
 3616        if reset {
 3617            let pointer_position = display_map
 3618                .buffer_snapshot
 3619                .anchor_before(position.to_point(&display_map));
 3620
 3621            self.change_selections(
 3622                SelectionEffects::scroll(Autoscroll::newest()),
 3623                window,
 3624                cx,
 3625                |s| {
 3626                    s.clear_disjoint();
 3627                    s.set_pending_anchor_range(
 3628                        pointer_position..pointer_position,
 3629                        SelectMode::Character,
 3630                    );
 3631                },
 3632            );
 3633        };
 3634
 3635        let tail = self.selections.newest::<Point>(cx).tail();
 3636        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3637        self.columnar_selection_state = match mode {
 3638            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3639                selection_tail: selection_anchor,
 3640                display_point: if reset {
 3641                    if position.column() != goal_column {
 3642                        Some(DisplayPoint::new(position.row(), goal_column))
 3643                    } else {
 3644                        None
 3645                    }
 3646                } else {
 3647                    None
 3648                },
 3649            }),
 3650            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3651                selection_tail: selection_anchor,
 3652            }),
 3653        };
 3654
 3655        if !reset {
 3656            self.select_columns(position, goal_column, &display_map, window, cx);
 3657        }
 3658    }
 3659
 3660    fn update_selection(
 3661        &mut self,
 3662        position: DisplayPoint,
 3663        goal_column: u32,
 3664        scroll_delta: gpui::Point<f32>,
 3665        window: &mut Window,
 3666        cx: &mut Context<Self>,
 3667    ) {
 3668        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3669
 3670        if self.columnar_selection_state.is_some() {
 3671            self.select_columns(position, goal_column, &display_map, window, cx);
 3672        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3673            let buffer = &display_map.buffer_snapshot;
 3674            let head;
 3675            let tail;
 3676            let mode = self.selections.pending_mode().unwrap();
 3677            match &mode {
 3678                SelectMode::Character => {
 3679                    head = position.to_point(&display_map);
 3680                    tail = pending.tail().to_point(buffer);
 3681                }
 3682                SelectMode::Word(original_range) => {
 3683                    let offset = display_map
 3684                        .clip_point(position, Bias::Left)
 3685                        .to_offset(&display_map, Bias::Left);
 3686                    let original_range = original_range.to_offset(buffer);
 3687
 3688                    let head_offset = if buffer.is_inside_word(offset, false)
 3689                        || original_range.contains(&offset)
 3690                    {
 3691                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3692                        if word_range.start < original_range.start {
 3693                            word_range.start
 3694                        } else {
 3695                            word_range.end
 3696                        }
 3697                    } else {
 3698                        offset
 3699                    };
 3700
 3701                    head = head_offset.to_point(buffer);
 3702                    if head_offset <= original_range.start {
 3703                        tail = original_range.end.to_point(buffer);
 3704                    } else {
 3705                        tail = original_range.start.to_point(buffer);
 3706                    }
 3707                }
 3708                SelectMode::Line(original_range) => {
 3709                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3710
 3711                    let position = display_map
 3712                        .clip_point(position, Bias::Left)
 3713                        .to_point(&display_map);
 3714                    let line_start = display_map.prev_line_boundary(position).0;
 3715                    let next_line_start = buffer.clip_point(
 3716                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3717                        Bias::Left,
 3718                    );
 3719
 3720                    if line_start < original_range.start {
 3721                        head = line_start
 3722                    } else {
 3723                        head = next_line_start
 3724                    }
 3725
 3726                    if head <= original_range.start {
 3727                        tail = original_range.end;
 3728                    } else {
 3729                        tail = original_range.start;
 3730                    }
 3731                }
 3732                SelectMode::All => {
 3733                    return;
 3734                }
 3735            };
 3736
 3737            if head < tail {
 3738                pending.start = buffer.anchor_before(head);
 3739                pending.end = buffer.anchor_before(tail);
 3740                pending.reversed = true;
 3741            } else {
 3742                pending.start = buffer.anchor_before(tail);
 3743                pending.end = buffer.anchor_before(head);
 3744                pending.reversed = false;
 3745            }
 3746
 3747            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3748                s.set_pending(pending, mode);
 3749            });
 3750        } else {
 3751            log::error!("update_selection dispatched with no pending selection");
 3752            return;
 3753        }
 3754
 3755        self.apply_scroll_delta(scroll_delta, window, cx);
 3756        cx.notify();
 3757    }
 3758
 3759    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3760        self.columnar_selection_state.take();
 3761        if self.selections.pending_anchor().is_some() {
 3762            let selections = self.selections.all::<usize>(cx);
 3763            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3764                s.select(selections);
 3765                s.clear_pending();
 3766            });
 3767        }
 3768    }
 3769
 3770    fn select_columns(
 3771        &mut self,
 3772        head: DisplayPoint,
 3773        goal_column: u32,
 3774        display_map: &DisplaySnapshot,
 3775        window: &mut Window,
 3776        cx: &mut Context<Self>,
 3777    ) {
 3778        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3779            return;
 3780        };
 3781
 3782        let tail = match columnar_state {
 3783            ColumnarSelectionState::FromMouse {
 3784                selection_tail,
 3785                display_point,
 3786            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3787            ColumnarSelectionState::FromSelection { selection_tail } => {
 3788                selection_tail.to_display_point(display_map)
 3789            }
 3790        };
 3791
 3792        let start_row = cmp::min(tail.row(), head.row());
 3793        let end_row = cmp::max(tail.row(), head.row());
 3794        let start_column = cmp::min(tail.column(), goal_column);
 3795        let end_column = cmp::max(tail.column(), goal_column);
 3796        let reversed = start_column < tail.column();
 3797
 3798        let selection_ranges = (start_row.0..=end_row.0)
 3799            .map(DisplayRow)
 3800            .filter_map(|row| {
 3801                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3802                    || start_column <= display_map.line_len(row))
 3803                    && !display_map.is_block_line(row)
 3804                {
 3805                    let start = display_map
 3806                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3807                        .to_point(display_map);
 3808                    let end = display_map
 3809                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3810                        .to_point(display_map);
 3811                    if reversed {
 3812                        Some(end..start)
 3813                    } else {
 3814                        Some(start..end)
 3815                    }
 3816                } else {
 3817                    None
 3818                }
 3819            })
 3820            .collect::<Vec<_>>();
 3821
 3822        let ranges = match columnar_state {
 3823            ColumnarSelectionState::FromMouse { .. } => {
 3824                let mut non_empty_ranges = selection_ranges
 3825                    .iter()
 3826                    .filter(|selection_range| selection_range.start != selection_range.end)
 3827                    .peekable();
 3828                if non_empty_ranges.peek().is_some() {
 3829                    non_empty_ranges.cloned().collect()
 3830                } else {
 3831                    selection_ranges
 3832                }
 3833            }
 3834            _ => selection_ranges,
 3835        };
 3836
 3837        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3838            s.select_ranges(ranges);
 3839        });
 3840        cx.notify();
 3841    }
 3842
 3843    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3844        self.selections
 3845            .all_adjusted(cx)
 3846            .iter()
 3847            .any(|selection| !selection.is_empty())
 3848    }
 3849
 3850    pub fn has_pending_nonempty_selection(&self) -> bool {
 3851        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3852            Some(Selection { start, end, .. }) => start != end,
 3853            None => false,
 3854        };
 3855
 3856        pending_nonempty_selection
 3857            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3858    }
 3859
 3860    pub fn has_pending_selection(&self) -> bool {
 3861        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3862    }
 3863
 3864    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3865        self.selection_mark_mode = false;
 3866        self.selection_drag_state = SelectionDragState::None;
 3867
 3868        if self.clear_expanded_diff_hunks(cx) {
 3869            cx.notify();
 3870            return;
 3871        }
 3872        if self.dismiss_menus_and_popups(true, window, cx) {
 3873            return;
 3874        }
 3875
 3876        if self.mode.is_full()
 3877            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3878        {
 3879            return;
 3880        }
 3881
 3882        cx.propagate();
 3883    }
 3884
 3885    pub fn dismiss_menus_and_popups(
 3886        &mut self,
 3887        is_user_requested: bool,
 3888        window: &mut Window,
 3889        cx: &mut Context<Self>,
 3890    ) -> bool {
 3891        if self.take_rename(false, window, cx).is_some() {
 3892            return true;
 3893        }
 3894
 3895        if hide_hover(self, cx) {
 3896            return true;
 3897        }
 3898
 3899        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3900            return true;
 3901        }
 3902
 3903        if self.hide_context_menu(window, cx).is_some() {
 3904            return true;
 3905        }
 3906
 3907        if self.mouse_context_menu.take().is_some() {
 3908            return true;
 3909        }
 3910
 3911        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3912            return true;
 3913        }
 3914
 3915        if self.snippet_stack.pop().is_some() {
 3916            return true;
 3917        }
 3918
 3919        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3920            self.dismiss_diagnostics(cx);
 3921            return true;
 3922        }
 3923
 3924        false
 3925    }
 3926
 3927    fn linked_editing_ranges_for(
 3928        &self,
 3929        selection: Range<text::Anchor>,
 3930        cx: &App,
 3931    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3932        if self.linked_edit_ranges.is_empty() {
 3933            return None;
 3934        }
 3935        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3936            selection.end.buffer_id.and_then(|end_buffer_id| {
 3937                if selection.start.buffer_id != Some(end_buffer_id) {
 3938                    return None;
 3939                }
 3940                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3941                let snapshot = buffer.read(cx).snapshot();
 3942                self.linked_edit_ranges
 3943                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3944                    .map(|ranges| (ranges, snapshot, buffer))
 3945            })?;
 3946        use text::ToOffset as TO;
 3947        // find offset from the start of current range to current cursor position
 3948        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3949
 3950        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3951        let start_difference = start_offset - start_byte_offset;
 3952        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3953        let end_difference = end_offset - start_byte_offset;
 3954        // Current range has associated linked ranges.
 3955        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3956        for range in linked_ranges.iter() {
 3957            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3958            let end_offset = start_offset + end_difference;
 3959            let start_offset = start_offset + start_difference;
 3960            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3961                continue;
 3962            }
 3963            if self.selections.disjoint_anchor_ranges().any(|s| {
 3964                if s.start.buffer_id != selection.start.buffer_id
 3965                    || s.end.buffer_id != selection.end.buffer_id
 3966                {
 3967                    return false;
 3968                }
 3969                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3970                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3971            }) {
 3972                continue;
 3973            }
 3974            let start = buffer_snapshot.anchor_after(start_offset);
 3975            let end = buffer_snapshot.anchor_after(end_offset);
 3976            linked_edits
 3977                .entry(buffer.clone())
 3978                .or_default()
 3979                .push(start..end);
 3980        }
 3981        Some(linked_edits)
 3982    }
 3983
 3984    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3985        let text: Arc<str> = text.into();
 3986
 3987        if self.read_only(cx) {
 3988            return;
 3989        }
 3990
 3991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3992
 3993        let selections = self.selections.all_adjusted(cx);
 3994        let mut bracket_inserted = false;
 3995        let mut edits = Vec::new();
 3996        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3997        let mut new_selections = Vec::with_capacity(selections.len());
 3998        let mut new_autoclose_regions = Vec::new();
 3999        let snapshot = self.buffer.read(cx).read(cx);
 4000        let mut clear_linked_edit_ranges = false;
 4001
 4002        for (selection, autoclose_region) in
 4003            self.selections_with_autoclose_regions(selections, &snapshot)
 4004        {
 4005            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4006                // Determine if the inserted text matches the opening or closing
 4007                // bracket of any of this language's bracket pairs.
 4008                let mut bracket_pair = None;
 4009                let mut is_bracket_pair_start = false;
 4010                let mut is_bracket_pair_end = false;
 4011                if !text.is_empty() {
 4012                    let mut bracket_pair_matching_end = None;
 4013                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4014                    //  and they are removing the character that triggered IME popup.
 4015                    for (pair, enabled) in scope.brackets() {
 4016                        if !pair.close && !pair.surround {
 4017                            continue;
 4018                        }
 4019
 4020                        if enabled && pair.start.ends_with(text.as_ref()) {
 4021                            let prefix_len = pair.start.len() - text.len();
 4022                            let preceding_text_matches_prefix = prefix_len == 0
 4023                                || (selection.start.column >= (prefix_len as u32)
 4024                                    && snapshot.contains_str_at(
 4025                                        Point::new(
 4026                                            selection.start.row,
 4027                                            selection.start.column - (prefix_len as u32),
 4028                                        ),
 4029                                        &pair.start[..prefix_len],
 4030                                    ));
 4031                            if preceding_text_matches_prefix {
 4032                                bracket_pair = Some(pair.clone());
 4033                                is_bracket_pair_start = true;
 4034                                break;
 4035                            }
 4036                        }
 4037                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4038                        {
 4039                            // take first bracket pair matching end, but don't break in case a later bracket
 4040                            // pair matches start
 4041                            bracket_pair_matching_end = Some(pair.clone());
 4042                        }
 4043                    }
 4044                    if let Some(end) = bracket_pair_matching_end
 4045                        && bracket_pair.is_none()
 4046                    {
 4047                        bracket_pair = Some(end);
 4048                        is_bracket_pair_end = true;
 4049                    }
 4050                }
 4051
 4052                if let Some(bracket_pair) = bracket_pair {
 4053                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4054                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4055                    let auto_surround =
 4056                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4057                    if selection.is_empty() {
 4058                        if is_bracket_pair_start {
 4059                            // If the inserted text is a suffix of an opening bracket and the
 4060                            // selection is preceded by the rest of the opening bracket, then
 4061                            // insert the closing bracket.
 4062                            let following_text_allows_autoclose = snapshot
 4063                                .chars_at(selection.start)
 4064                                .next()
 4065                                .is_none_or(|c| scope.should_autoclose_before(c));
 4066
 4067                            let preceding_text_allows_autoclose = selection.start.column == 0
 4068                                || snapshot
 4069                                    .reversed_chars_at(selection.start)
 4070                                    .next()
 4071                                    .is_none_or(|c| {
 4072                                        bracket_pair.start != bracket_pair.end
 4073                                            || !snapshot
 4074                                                .char_classifier_at(selection.start)
 4075                                                .is_word(c)
 4076                                    });
 4077
 4078                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4079                                && bracket_pair.start.len() == 1
 4080                            {
 4081                                let target = bracket_pair.start.chars().next().unwrap();
 4082                                let current_line_count = snapshot
 4083                                    .reversed_chars_at(selection.start)
 4084                                    .take_while(|&c| c != '\n')
 4085                                    .filter(|&c| c == target)
 4086                                    .count();
 4087                                current_line_count % 2 == 1
 4088                            } else {
 4089                                false
 4090                            };
 4091
 4092                            if autoclose
 4093                                && bracket_pair.close
 4094                                && following_text_allows_autoclose
 4095                                && preceding_text_allows_autoclose
 4096                                && !is_closing_quote
 4097                            {
 4098                                let anchor = snapshot.anchor_before(selection.end);
 4099                                new_selections.push((selection.map(|_| anchor), text.len()));
 4100                                new_autoclose_regions.push((
 4101                                    anchor,
 4102                                    text.len(),
 4103                                    selection.id,
 4104                                    bracket_pair.clone(),
 4105                                ));
 4106                                edits.push((
 4107                                    selection.range(),
 4108                                    format!("{}{}", text, bracket_pair.end).into(),
 4109                                ));
 4110                                bracket_inserted = true;
 4111                                continue;
 4112                            }
 4113                        }
 4114
 4115                        if let Some(region) = autoclose_region {
 4116                            // If the selection is followed by an auto-inserted closing bracket,
 4117                            // then don't insert that closing bracket again; just move the selection
 4118                            // past the closing bracket.
 4119                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4120                                && text.as_ref() == region.pair.end.as_str()
 4121                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4122                            if should_skip {
 4123                                let anchor = snapshot.anchor_after(selection.end);
 4124                                new_selections
 4125                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4126                                continue;
 4127                            }
 4128                        }
 4129
 4130                        let always_treat_brackets_as_autoclosed = snapshot
 4131                            .language_settings_at(selection.start, cx)
 4132                            .always_treat_brackets_as_autoclosed;
 4133                        if always_treat_brackets_as_autoclosed
 4134                            && is_bracket_pair_end
 4135                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4136                        {
 4137                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4138                            // and the inserted text is a closing bracket and the selection is followed
 4139                            // by the closing bracket then move the selection past the closing bracket.
 4140                            let anchor = snapshot.anchor_after(selection.end);
 4141                            new_selections.push((selection.map(|_| anchor), text.len()));
 4142                            continue;
 4143                        }
 4144                    }
 4145                    // If an opening bracket is 1 character long and is typed while
 4146                    // text is selected, then surround that text with the bracket pair.
 4147                    else if auto_surround
 4148                        && bracket_pair.surround
 4149                        && is_bracket_pair_start
 4150                        && bracket_pair.start.chars().count() == 1
 4151                    {
 4152                        edits.push((selection.start..selection.start, text.clone()));
 4153                        edits.push((
 4154                            selection.end..selection.end,
 4155                            bracket_pair.end.as_str().into(),
 4156                        ));
 4157                        bracket_inserted = true;
 4158                        new_selections.push((
 4159                            Selection {
 4160                                id: selection.id,
 4161                                start: snapshot.anchor_after(selection.start),
 4162                                end: snapshot.anchor_before(selection.end),
 4163                                reversed: selection.reversed,
 4164                                goal: selection.goal,
 4165                            },
 4166                            0,
 4167                        ));
 4168                        continue;
 4169                    }
 4170                }
 4171            }
 4172
 4173            if self.auto_replace_emoji_shortcode
 4174                && selection.is_empty()
 4175                && text.as_ref().ends_with(':')
 4176                && let Some(possible_emoji_short_code) =
 4177                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4178                && !possible_emoji_short_code.is_empty()
 4179                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4180            {
 4181                let emoji_shortcode_start = Point::new(
 4182                    selection.start.row,
 4183                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4184                );
 4185
 4186                // Remove shortcode from buffer
 4187                edits.push((
 4188                    emoji_shortcode_start..selection.start,
 4189                    "".to_string().into(),
 4190                ));
 4191                new_selections.push((
 4192                    Selection {
 4193                        id: selection.id,
 4194                        start: snapshot.anchor_after(emoji_shortcode_start),
 4195                        end: snapshot.anchor_before(selection.start),
 4196                        reversed: selection.reversed,
 4197                        goal: selection.goal,
 4198                    },
 4199                    0,
 4200                ));
 4201
 4202                // Insert emoji
 4203                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4204                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4205                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4206
 4207                continue;
 4208            }
 4209
 4210            // If not handling any auto-close operation, then just replace the selected
 4211            // text with the given input and move the selection to the end of the
 4212            // newly inserted text.
 4213            let anchor = snapshot.anchor_after(selection.end);
 4214            if !self.linked_edit_ranges.is_empty() {
 4215                let start_anchor = snapshot.anchor_before(selection.start);
 4216
 4217                let is_word_char = text.chars().next().is_none_or(|char| {
 4218                    let classifier = snapshot
 4219                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4220                        .ignore_punctuation(true);
 4221                    classifier.is_word(char)
 4222                });
 4223
 4224                if is_word_char {
 4225                    if let Some(ranges) = self
 4226                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4227                    {
 4228                        for (buffer, edits) in ranges {
 4229                            linked_edits
 4230                                .entry(buffer.clone())
 4231                                .or_default()
 4232                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4233                        }
 4234                    }
 4235                } else {
 4236                    clear_linked_edit_ranges = true;
 4237                }
 4238            }
 4239
 4240            new_selections.push((selection.map(|_| anchor), 0));
 4241            edits.push((selection.start..selection.end, text.clone()));
 4242        }
 4243
 4244        drop(snapshot);
 4245
 4246        self.transact(window, cx, |this, window, cx| {
 4247            if clear_linked_edit_ranges {
 4248                this.linked_edit_ranges.clear();
 4249            }
 4250            let initial_buffer_versions =
 4251                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4252
 4253            this.buffer.update(cx, |buffer, cx| {
 4254                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4255            });
 4256            for (buffer, edits) in linked_edits {
 4257                buffer.update(cx, |buffer, cx| {
 4258                    let snapshot = buffer.snapshot();
 4259                    let edits = edits
 4260                        .into_iter()
 4261                        .map(|(range, text)| {
 4262                            use text::ToPoint as TP;
 4263                            let end_point = TP::to_point(&range.end, &snapshot);
 4264                            let start_point = TP::to_point(&range.start, &snapshot);
 4265                            (start_point..end_point, text)
 4266                        })
 4267                        .sorted_by_key(|(range, _)| range.start);
 4268                    buffer.edit(edits, None, cx);
 4269                })
 4270            }
 4271            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4272            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4273            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4274            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4275                .zip(new_selection_deltas)
 4276                .map(|(selection, delta)| Selection {
 4277                    id: selection.id,
 4278                    start: selection.start + delta,
 4279                    end: selection.end + delta,
 4280                    reversed: selection.reversed,
 4281                    goal: SelectionGoal::None,
 4282                })
 4283                .collect::<Vec<_>>();
 4284
 4285            let mut i = 0;
 4286            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4287                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4288                let start = map.buffer_snapshot.anchor_before(position);
 4289                let end = map.buffer_snapshot.anchor_after(position);
 4290                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4291                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4292                        Ordering::Less => i += 1,
 4293                        Ordering::Greater => break,
 4294                        Ordering::Equal => {
 4295                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4296                                Ordering::Less => i += 1,
 4297                                Ordering::Equal => break,
 4298                                Ordering::Greater => break,
 4299                            }
 4300                        }
 4301                    }
 4302                }
 4303                this.autoclose_regions.insert(
 4304                    i,
 4305                    AutocloseRegion {
 4306                        selection_id,
 4307                        range: start..end,
 4308                        pair,
 4309                    },
 4310                );
 4311            }
 4312
 4313            let had_active_edit_prediction = this.has_active_edit_prediction();
 4314            this.change_selections(
 4315                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4316                window,
 4317                cx,
 4318                |s| s.select(new_selections),
 4319            );
 4320
 4321            if !bracket_inserted
 4322                && let Some(on_type_format_task) =
 4323                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4324            {
 4325                on_type_format_task.detach_and_log_err(cx);
 4326            }
 4327
 4328            let editor_settings = EditorSettings::get_global(cx);
 4329            if bracket_inserted
 4330                && (editor_settings.auto_signature_help
 4331                    || editor_settings.show_signature_help_after_edits)
 4332            {
 4333                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4334            }
 4335
 4336            let trigger_in_words =
 4337                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4338            if this.hard_wrap.is_some() {
 4339                let latest: Range<Point> = this.selections.newest(cx).range();
 4340                if latest.is_empty()
 4341                    && this
 4342                        .buffer()
 4343                        .read(cx)
 4344                        .snapshot(cx)
 4345                        .line_len(MultiBufferRow(latest.start.row))
 4346                        == latest.start.column
 4347                {
 4348                    this.rewrap_impl(
 4349                        RewrapOptions {
 4350                            override_language_settings: true,
 4351                            preserve_existing_whitespace: true,
 4352                        },
 4353                        cx,
 4354                    )
 4355                }
 4356            }
 4357            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4358            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4359            this.refresh_edit_prediction(true, false, window, cx);
 4360            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4361        });
 4362    }
 4363
 4364    fn find_possible_emoji_shortcode_at_position(
 4365        snapshot: &MultiBufferSnapshot,
 4366        position: Point,
 4367    ) -> Option<String> {
 4368        let mut chars = Vec::new();
 4369        let mut found_colon = false;
 4370        for char in snapshot.reversed_chars_at(position).take(100) {
 4371            // Found a possible emoji shortcode in the middle of the buffer
 4372            if found_colon {
 4373                if char.is_whitespace() {
 4374                    chars.reverse();
 4375                    return Some(chars.iter().collect());
 4376                }
 4377                // If the previous character is not a whitespace, we are in the middle of a word
 4378                // and we only want to complete the shortcode if the word is made up of other emojis
 4379                let mut containing_word = String::new();
 4380                for ch in snapshot
 4381                    .reversed_chars_at(position)
 4382                    .skip(chars.len() + 1)
 4383                    .take(100)
 4384                {
 4385                    if ch.is_whitespace() {
 4386                        break;
 4387                    }
 4388                    containing_word.push(ch);
 4389                }
 4390                let containing_word = containing_word.chars().rev().collect::<String>();
 4391                if util::word_consists_of_emojis(containing_word.as_str()) {
 4392                    chars.reverse();
 4393                    return Some(chars.iter().collect());
 4394                }
 4395            }
 4396
 4397            if char.is_whitespace() || !char.is_ascii() {
 4398                return None;
 4399            }
 4400            if char == ':' {
 4401                found_colon = true;
 4402            } else {
 4403                chars.push(char);
 4404            }
 4405        }
 4406        // Found a possible emoji shortcode at the beginning of the buffer
 4407        chars.reverse();
 4408        Some(chars.iter().collect())
 4409    }
 4410
 4411    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4412        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4413        self.transact(window, cx, |this, window, cx| {
 4414            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4415                let selections = this.selections.all::<usize>(cx);
 4416                let multi_buffer = this.buffer.read(cx);
 4417                let buffer = multi_buffer.snapshot(cx);
 4418                selections
 4419                    .iter()
 4420                    .map(|selection| {
 4421                        let start_point = selection.start.to_point(&buffer);
 4422                        let mut existing_indent =
 4423                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4424                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4425                        let start = selection.start;
 4426                        let end = selection.end;
 4427                        let selection_is_empty = start == end;
 4428                        let language_scope = buffer.language_scope_at(start);
 4429                        let (
 4430                            comment_delimiter,
 4431                            doc_delimiter,
 4432                            insert_extra_newline,
 4433                            indent_on_newline,
 4434                            indent_on_extra_newline,
 4435                        ) = if let Some(language) = &language_scope {
 4436                            let mut insert_extra_newline =
 4437                                insert_extra_newline_brackets(&buffer, start..end, language)
 4438                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4439
 4440                            // Comment extension on newline is allowed only for cursor selections
 4441                            let comment_delimiter = maybe!({
 4442                                if !selection_is_empty {
 4443                                    return None;
 4444                                }
 4445
 4446                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4447                                    return None;
 4448                                }
 4449
 4450                                let delimiters = language.line_comment_prefixes();
 4451                                let max_len_of_delimiter =
 4452                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4453                                let (snapshot, range) =
 4454                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4455
 4456                                let num_of_whitespaces = snapshot
 4457                                    .chars_for_range(range.clone())
 4458                                    .take_while(|c| c.is_whitespace())
 4459                                    .count();
 4460                                let comment_candidate = snapshot
 4461                                    .chars_for_range(range.clone())
 4462                                    .skip(num_of_whitespaces)
 4463                                    .take(max_len_of_delimiter)
 4464                                    .collect::<String>();
 4465                                let (delimiter, trimmed_len) = delimiters
 4466                                    .iter()
 4467                                    .filter_map(|delimiter| {
 4468                                        let prefix = delimiter.trim_end();
 4469                                        if comment_candidate.starts_with(prefix) {
 4470                                            Some((delimiter, prefix.len()))
 4471                                        } else {
 4472                                            None
 4473                                        }
 4474                                    })
 4475                                    .max_by_key(|(_, len)| *len)?;
 4476
 4477                                if let Some(BlockCommentConfig {
 4478                                    start: block_start, ..
 4479                                }) = language.block_comment()
 4480                                {
 4481                                    let block_start_trimmed = block_start.trim_end();
 4482                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4483                                        let line_content = snapshot
 4484                                            .chars_for_range(range)
 4485                                            .skip(num_of_whitespaces)
 4486                                            .take(block_start_trimmed.len())
 4487                                            .collect::<String>();
 4488
 4489                                        if line_content.starts_with(block_start_trimmed) {
 4490                                            return None;
 4491                                        }
 4492                                    }
 4493                                }
 4494
 4495                                let cursor_is_placed_after_comment_marker =
 4496                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4497                                if cursor_is_placed_after_comment_marker {
 4498                                    Some(delimiter.clone())
 4499                                } else {
 4500                                    None
 4501                                }
 4502                            });
 4503
 4504                            let mut indent_on_newline = IndentSize::spaces(0);
 4505                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4506
 4507                            let doc_delimiter = maybe!({
 4508                                if !selection_is_empty {
 4509                                    return None;
 4510                                }
 4511
 4512                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4513                                    return None;
 4514                                }
 4515
 4516                                let BlockCommentConfig {
 4517                                    start: start_tag,
 4518                                    end: end_tag,
 4519                                    prefix: delimiter,
 4520                                    tab_size: len,
 4521                                } = language.documentation_comment()?;
 4522                                let is_within_block_comment = buffer
 4523                                    .language_scope_at(start_point)
 4524                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4525                                if !is_within_block_comment {
 4526                                    return None;
 4527                                }
 4528
 4529                                let (snapshot, range) =
 4530                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4531
 4532                                let num_of_whitespaces = snapshot
 4533                                    .chars_for_range(range.clone())
 4534                                    .take_while(|c| c.is_whitespace())
 4535                                    .count();
 4536
 4537                                // 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.
 4538                                let column = start_point.column;
 4539                                let cursor_is_after_start_tag = {
 4540                                    let start_tag_len = start_tag.len();
 4541                                    let start_tag_line = snapshot
 4542                                        .chars_for_range(range.clone())
 4543                                        .skip(num_of_whitespaces)
 4544                                        .take(start_tag_len)
 4545                                        .collect::<String>();
 4546                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4547                                        num_of_whitespaces + start_tag_len <= column as usize
 4548                                    } else {
 4549                                        false
 4550                                    }
 4551                                };
 4552
 4553                                let cursor_is_after_delimiter = {
 4554                                    let delimiter_trim = delimiter.trim_end();
 4555                                    let delimiter_line = snapshot
 4556                                        .chars_for_range(range.clone())
 4557                                        .skip(num_of_whitespaces)
 4558                                        .take(delimiter_trim.len())
 4559                                        .collect::<String>();
 4560                                    if delimiter_line.starts_with(delimiter_trim) {
 4561                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4562                                    } else {
 4563                                        false
 4564                                    }
 4565                                };
 4566
 4567                                let cursor_is_before_end_tag_if_exists = {
 4568                                    let mut char_position = 0u32;
 4569                                    let mut end_tag_offset = None;
 4570
 4571                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4572                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4573                                            let chars_before_match =
 4574                                                chunk[..byte_pos].chars().count() as u32;
 4575                                            end_tag_offset =
 4576                                                Some(char_position + chars_before_match);
 4577                                            break 'outer;
 4578                                        }
 4579                                        char_position += chunk.chars().count() as u32;
 4580                                    }
 4581
 4582                                    if let Some(end_tag_offset) = end_tag_offset {
 4583                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4584                                        if cursor_is_after_start_tag {
 4585                                            if cursor_is_before_end_tag {
 4586                                                insert_extra_newline = true;
 4587                                            }
 4588                                            let cursor_is_at_start_of_end_tag =
 4589                                                column == end_tag_offset;
 4590                                            if cursor_is_at_start_of_end_tag {
 4591                                                indent_on_extra_newline.len = *len;
 4592                                            }
 4593                                        }
 4594                                        cursor_is_before_end_tag
 4595                                    } else {
 4596                                        true
 4597                                    }
 4598                                };
 4599
 4600                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4601                                    && cursor_is_before_end_tag_if_exists
 4602                                {
 4603                                    if cursor_is_after_start_tag {
 4604                                        indent_on_newline.len = *len;
 4605                                    }
 4606                                    Some(delimiter.clone())
 4607                                } else {
 4608                                    None
 4609                                }
 4610                            });
 4611
 4612                            (
 4613                                comment_delimiter,
 4614                                doc_delimiter,
 4615                                insert_extra_newline,
 4616                                indent_on_newline,
 4617                                indent_on_extra_newline,
 4618                            )
 4619                        } else {
 4620                            (
 4621                                None,
 4622                                None,
 4623                                false,
 4624                                IndentSize::default(),
 4625                                IndentSize::default(),
 4626                            )
 4627                        };
 4628
 4629                        let prevent_auto_indent = doc_delimiter.is_some();
 4630                        let delimiter = comment_delimiter.or(doc_delimiter);
 4631
 4632                        let capacity_for_delimiter =
 4633                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4634                        let mut new_text = String::with_capacity(
 4635                            1 + capacity_for_delimiter
 4636                                + existing_indent.len as usize
 4637                                + indent_on_newline.len as usize
 4638                                + indent_on_extra_newline.len as usize,
 4639                        );
 4640                        new_text.push('\n');
 4641                        new_text.extend(existing_indent.chars());
 4642                        new_text.extend(indent_on_newline.chars());
 4643
 4644                        if let Some(delimiter) = &delimiter {
 4645                            new_text.push_str(delimiter);
 4646                        }
 4647
 4648                        if insert_extra_newline {
 4649                            new_text.push('\n');
 4650                            new_text.extend(existing_indent.chars());
 4651                            new_text.extend(indent_on_extra_newline.chars());
 4652                        }
 4653
 4654                        let anchor = buffer.anchor_after(end);
 4655                        let new_selection = selection.map(|_| anchor);
 4656                        (
 4657                            ((start..end, new_text), prevent_auto_indent),
 4658                            (insert_extra_newline, new_selection),
 4659                        )
 4660                    })
 4661                    .unzip()
 4662            };
 4663
 4664            let mut auto_indent_edits = Vec::new();
 4665            let mut edits = Vec::new();
 4666            for (edit, prevent_auto_indent) in edits_with_flags {
 4667                if prevent_auto_indent {
 4668                    edits.push(edit);
 4669                } else {
 4670                    auto_indent_edits.push(edit);
 4671                }
 4672            }
 4673            if !edits.is_empty() {
 4674                this.edit(edits, cx);
 4675            }
 4676            if !auto_indent_edits.is_empty() {
 4677                this.edit_with_autoindent(auto_indent_edits, cx);
 4678            }
 4679
 4680            let buffer = this.buffer.read(cx).snapshot(cx);
 4681            let new_selections = selection_info
 4682                .into_iter()
 4683                .map(|(extra_newline_inserted, new_selection)| {
 4684                    let mut cursor = new_selection.end.to_point(&buffer);
 4685                    if extra_newline_inserted {
 4686                        cursor.row -= 1;
 4687                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4688                    }
 4689                    new_selection.map(|_| cursor)
 4690                })
 4691                .collect();
 4692
 4693            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4694            this.refresh_edit_prediction(true, false, window, cx);
 4695        });
 4696    }
 4697
 4698    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4699        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4700
 4701        let buffer = self.buffer.read(cx);
 4702        let snapshot = buffer.snapshot(cx);
 4703
 4704        let mut edits = Vec::new();
 4705        let mut rows = Vec::new();
 4706
 4707        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4708            let cursor = selection.head();
 4709            let row = cursor.row;
 4710
 4711            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4712
 4713            let newline = "\n".to_string();
 4714            edits.push((start_of_line..start_of_line, newline));
 4715
 4716            rows.push(row + rows_inserted as u32);
 4717        }
 4718
 4719        self.transact(window, cx, |editor, window, cx| {
 4720            editor.edit(edits, cx);
 4721
 4722            editor.change_selections(Default::default(), window, cx, |s| {
 4723                let mut index = 0;
 4724                s.move_cursors_with(|map, _, _| {
 4725                    let row = rows[index];
 4726                    index += 1;
 4727
 4728                    let point = Point::new(row, 0);
 4729                    let boundary = map.next_line_boundary(point).1;
 4730                    let clipped = map.clip_point(boundary, Bias::Left);
 4731
 4732                    (clipped, SelectionGoal::None)
 4733                });
 4734            });
 4735
 4736            let mut indent_edits = Vec::new();
 4737            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4738            for row in rows {
 4739                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4740                for (row, indent) in indents {
 4741                    if indent.len == 0 {
 4742                        continue;
 4743                    }
 4744
 4745                    let text = match indent.kind {
 4746                        IndentKind::Space => " ".repeat(indent.len as usize),
 4747                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4748                    };
 4749                    let point = Point::new(row.0, 0);
 4750                    indent_edits.push((point..point, text));
 4751                }
 4752            }
 4753            editor.edit(indent_edits, cx);
 4754        });
 4755    }
 4756
 4757    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4759
 4760        let buffer = self.buffer.read(cx);
 4761        let snapshot = buffer.snapshot(cx);
 4762
 4763        let mut edits = Vec::new();
 4764        let mut rows = Vec::new();
 4765        let mut rows_inserted = 0;
 4766
 4767        for selection in self.selections.all_adjusted(cx) {
 4768            let cursor = selection.head();
 4769            let row = cursor.row;
 4770
 4771            let point = Point::new(row + 1, 0);
 4772            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4773
 4774            let newline = "\n".to_string();
 4775            edits.push((start_of_line..start_of_line, newline));
 4776
 4777            rows_inserted += 1;
 4778            rows.push(row + rows_inserted);
 4779        }
 4780
 4781        self.transact(window, cx, |editor, window, cx| {
 4782            editor.edit(edits, cx);
 4783
 4784            editor.change_selections(Default::default(), window, cx, |s| {
 4785                let mut index = 0;
 4786                s.move_cursors_with(|map, _, _| {
 4787                    let row = rows[index];
 4788                    index += 1;
 4789
 4790                    let point = Point::new(row, 0);
 4791                    let boundary = map.next_line_boundary(point).1;
 4792                    let clipped = map.clip_point(boundary, Bias::Left);
 4793
 4794                    (clipped, SelectionGoal::None)
 4795                });
 4796            });
 4797
 4798            let mut indent_edits = Vec::new();
 4799            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4800            for row in rows {
 4801                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4802                for (row, indent) in indents {
 4803                    if indent.len == 0 {
 4804                        continue;
 4805                    }
 4806
 4807                    let text = match indent.kind {
 4808                        IndentKind::Space => " ".repeat(indent.len as usize),
 4809                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4810                    };
 4811                    let point = Point::new(row.0, 0);
 4812                    indent_edits.push((point..point, text));
 4813                }
 4814            }
 4815            editor.edit(indent_edits, cx);
 4816        });
 4817    }
 4818
 4819    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4820        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4821            original_indent_columns: Vec::new(),
 4822        });
 4823        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4824    }
 4825
 4826    fn insert_with_autoindent_mode(
 4827        &mut self,
 4828        text: &str,
 4829        autoindent_mode: Option<AutoindentMode>,
 4830        window: &mut Window,
 4831        cx: &mut Context<Self>,
 4832    ) {
 4833        if self.read_only(cx) {
 4834            return;
 4835        }
 4836
 4837        let text: Arc<str> = text.into();
 4838        self.transact(window, cx, |this, window, cx| {
 4839            let old_selections = this.selections.all_adjusted(cx);
 4840            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4841                let anchors = {
 4842                    let snapshot = buffer.read(cx);
 4843                    old_selections
 4844                        .iter()
 4845                        .map(|s| {
 4846                            let anchor = snapshot.anchor_after(s.head());
 4847                            s.map(|_| anchor)
 4848                        })
 4849                        .collect::<Vec<_>>()
 4850                };
 4851                buffer.edit(
 4852                    old_selections
 4853                        .iter()
 4854                        .map(|s| (s.start..s.end, text.clone())),
 4855                    autoindent_mode,
 4856                    cx,
 4857                );
 4858                anchors
 4859            });
 4860
 4861            this.change_selections(Default::default(), window, cx, |s| {
 4862                s.select_anchors(selection_anchors);
 4863            });
 4864
 4865            cx.notify();
 4866        });
 4867    }
 4868
 4869    fn trigger_completion_on_input(
 4870        &mut self,
 4871        text: &str,
 4872        trigger_in_words: bool,
 4873        window: &mut Window,
 4874        cx: &mut Context<Self>,
 4875    ) {
 4876        let completions_source = self
 4877            .context_menu
 4878            .borrow()
 4879            .as_ref()
 4880            .and_then(|menu| match menu {
 4881                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4882                CodeContextMenu::CodeActions(_) => None,
 4883            });
 4884
 4885        match completions_source {
 4886            Some(CompletionsMenuSource::Words) => {
 4887                self.show_word_completions(&ShowWordCompletions, window, cx)
 4888            }
 4889            Some(CompletionsMenuSource::Normal)
 4890            | Some(CompletionsMenuSource::SnippetChoices)
 4891            | None
 4892                if self.is_completion_trigger(
 4893                    text,
 4894                    trigger_in_words,
 4895                    completions_source.is_some(),
 4896                    cx,
 4897                ) =>
 4898            {
 4899                self.show_completions(
 4900                    &ShowCompletions {
 4901                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4902                    },
 4903                    window,
 4904                    cx,
 4905                )
 4906            }
 4907            _ => {
 4908                self.hide_context_menu(window, cx);
 4909            }
 4910        }
 4911    }
 4912
 4913    fn is_completion_trigger(
 4914        &self,
 4915        text: &str,
 4916        trigger_in_words: bool,
 4917        menu_is_open: bool,
 4918        cx: &mut Context<Self>,
 4919    ) -> bool {
 4920        let position = self.selections.newest_anchor().head();
 4921        let multibuffer = self.buffer.read(cx);
 4922        let Some(buffer) = position
 4923            .buffer_id
 4924            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4925        else {
 4926            return false;
 4927        };
 4928
 4929        if let Some(completion_provider) = &self.completion_provider {
 4930            completion_provider.is_completion_trigger(
 4931                &buffer,
 4932                position.text_anchor,
 4933                text,
 4934                trigger_in_words,
 4935                menu_is_open,
 4936                cx,
 4937            )
 4938        } else {
 4939            false
 4940        }
 4941    }
 4942
 4943    /// If any empty selections is touching the start of its innermost containing autoclose
 4944    /// region, expand it to select the brackets.
 4945    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4946        let selections = self.selections.all::<usize>(cx);
 4947        let buffer = self.buffer.read(cx).read(cx);
 4948        let new_selections = self
 4949            .selections_with_autoclose_regions(selections, &buffer)
 4950            .map(|(mut selection, region)| {
 4951                if !selection.is_empty() {
 4952                    return selection;
 4953                }
 4954
 4955                if let Some(region) = region {
 4956                    let mut range = region.range.to_offset(&buffer);
 4957                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4958                        range.start -= region.pair.start.len();
 4959                        if buffer.contains_str_at(range.start, &region.pair.start)
 4960                            && buffer.contains_str_at(range.end, &region.pair.end)
 4961                        {
 4962                            range.end += region.pair.end.len();
 4963                            selection.start = range.start;
 4964                            selection.end = range.end;
 4965
 4966                            return selection;
 4967                        }
 4968                    }
 4969                }
 4970
 4971                let always_treat_brackets_as_autoclosed = buffer
 4972                    .language_settings_at(selection.start, cx)
 4973                    .always_treat_brackets_as_autoclosed;
 4974
 4975                if !always_treat_brackets_as_autoclosed {
 4976                    return selection;
 4977                }
 4978
 4979                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4980                    for (pair, enabled) in scope.brackets() {
 4981                        if !enabled || !pair.close {
 4982                            continue;
 4983                        }
 4984
 4985                        if buffer.contains_str_at(selection.start, &pair.end) {
 4986                            let pair_start_len = pair.start.len();
 4987                            if buffer.contains_str_at(
 4988                                selection.start.saturating_sub(pair_start_len),
 4989                                &pair.start,
 4990                            ) {
 4991                                selection.start -= pair_start_len;
 4992                                selection.end += pair.end.len();
 4993
 4994                                return selection;
 4995                            }
 4996                        }
 4997                    }
 4998                }
 4999
 5000                selection
 5001            })
 5002            .collect();
 5003
 5004        drop(buffer);
 5005        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5006            selections.select(new_selections)
 5007        });
 5008    }
 5009
 5010    /// Iterate the given selections, and for each one, find the smallest surrounding
 5011    /// autoclose region. This uses the ordering of the selections and the autoclose
 5012    /// regions to avoid repeated comparisons.
 5013    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5014        &'a self,
 5015        selections: impl IntoIterator<Item = Selection<D>>,
 5016        buffer: &'a MultiBufferSnapshot,
 5017    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5018        let mut i = 0;
 5019        let mut regions = self.autoclose_regions.as_slice();
 5020        selections.into_iter().map(move |selection| {
 5021            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5022
 5023            let mut enclosing = None;
 5024            while let Some(pair_state) = regions.get(i) {
 5025                if pair_state.range.end.to_offset(buffer) < range.start {
 5026                    regions = &regions[i + 1..];
 5027                    i = 0;
 5028                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5029                    break;
 5030                } else {
 5031                    if pair_state.selection_id == selection.id {
 5032                        enclosing = Some(pair_state);
 5033                    }
 5034                    i += 1;
 5035                }
 5036            }
 5037
 5038            (selection, enclosing)
 5039        })
 5040    }
 5041
 5042    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5043    fn invalidate_autoclose_regions(
 5044        &mut self,
 5045        mut selections: &[Selection<Anchor>],
 5046        buffer: &MultiBufferSnapshot,
 5047    ) {
 5048        self.autoclose_regions.retain(|state| {
 5049            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5050                return false;
 5051            }
 5052
 5053            let mut i = 0;
 5054            while let Some(selection) = selections.get(i) {
 5055                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5056                    selections = &selections[1..];
 5057                    continue;
 5058                }
 5059                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5060                    break;
 5061                }
 5062                if selection.id == state.selection_id {
 5063                    return true;
 5064                } else {
 5065                    i += 1;
 5066                }
 5067            }
 5068            false
 5069        });
 5070    }
 5071
 5072    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5073        let offset = position.to_offset(buffer);
 5074        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5075        if offset > word_range.start && kind == Some(CharKind::Word) {
 5076            Some(
 5077                buffer
 5078                    .text_for_range(word_range.start..offset)
 5079                    .collect::<String>(),
 5080            )
 5081        } else {
 5082            None
 5083        }
 5084    }
 5085
 5086    pub fn toggle_inline_values(
 5087        &mut self,
 5088        _: &ToggleInlineValues,
 5089        _: &mut Window,
 5090        cx: &mut Context<Self>,
 5091    ) {
 5092        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5093
 5094        self.refresh_inline_values(cx);
 5095    }
 5096
 5097    pub fn toggle_inlay_hints(
 5098        &mut self,
 5099        _: &ToggleInlayHints,
 5100        _: &mut Window,
 5101        cx: &mut Context<Self>,
 5102    ) {
 5103        self.refresh_inlay_hints(
 5104            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5105            cx,
 5106        );
 5107    }
 5108
 5109    pub fn inlay_hints_enabled(&self) -> bool {
 5110        self.inlay_hint_cache.enabled
 5111    }
 5112
 5113    pub fn inline_values_enabled(&self) -> bool {
 5114        self.inline_value_cache.enabled
 5115    }
 5116
 5117    #[cfg(any(test, feature = "test-support"))]
 5118    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5119        self.display_map
 5120            .read(cx)
 5121            .current_inlays()
 5122            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5123            .cloned()
 5124            .collect()
 5125    }
 5126
 5127    #[cfg(any(test, feature = "test-support"))]
 5128    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5129        self.display_map
 5130            .read(cx)
 5131            .current_inlays()
 5132            .cloned()
 5133            .collect()
 5134    }
 5135
 5136    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5137        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5138            return;
 5139        }
 5140
 5141        let reason_description = reason.description();
 5142        let ignore_debounce = matches!(
 5143            reason,
 5144            InlayHintRefreshReason::SettingsChange(_)
 5145                | InlayHintRefreshReason::Toggle(_)
 5146                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5147                | InlayHintRefreshReason::ModifiersChanged(_)
 5148        );
 5149        let (invalidate_cache, required_languages) = match reason {
 5150            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5151                match self.inlay_hint_cache.modifiers_override(enabled) {
 5152                    Some(enabled) => {
 5153                        if enabled {
 5154                            (InvalidationStrategy::RefreshRequested, None)
 5155                        } else {
 5156                            self.splice_inlays(
 5157                                &self
 5158                                    .visible_inlay_hints(cx)
 5159                                    .iter()
 5160                                    .map(|inlay| inlay.id)
 5161                                    .collect::<Vec<InlayId>>(),
 5162                                Vec::new(),
 5163                                cx,
 5164                            );
 5165                            return;
 5166                        }
 5167                    }
 5168                    None => return,
 5169                }
 5170            }
 5171            InlayHintRefreshReason::Toggle(enabled) => {
 5172                if self.inlay_hint_cache.toggle(enabled) {
 5173                    if enabled {
 5174                        (InvalidationStrategy::RefreshRequested, None)
 5175                    } else {
 5176                        self.splice_inlays(
 5177                            &self
 5178                                .visible_inlay_hints(cx)
 5179                                .iter()
 5180                                .map(|inlay| inlay.id)
 5181                                .collect::<Vec<InlayId>>(),
 5182                            Vec::new(),
 5183                            cx,
 5184                        );
 5185                        return;
 5186                    }
 5187                } else {
 5188                    return;
 5189                }
 5190            }
 5191            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5192                match self.inlay_hint_cache.update_settings(
 5193                    &self.buffer,
 5194                    new_settings,
 5195                    self.visible_inlay_hints(cx),
 5196                    cx,
 5197                ) {
 5198                    ControlFlow::Break(Some(InlaySplice {
 5199                        to_remove,
 5200                        to_insert,
 5201                    })) => {
 5202                        self.splice_inlays(&to_remove, to_insert, cx);
 5203                        return;
 5204                    }
 5205                    ControlFlow::Break(None) => return,
 5206                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5207                }
 5208            }
 5209            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5210                if let Some(InlaySplice {
 5211                    to_remove,
 5212                    to_insert,
 5213                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5214                {
 5215                    self.splice_inlays(&to_remove, to_insert, cx);
 5216                }
 5217                self.display_map.update(cx, |display_map, _| {
 5218                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5219                });
 5220                return;
 5221            }
 5222            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5223            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5224                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5225            }
 5226            InlayHintRefreshReason::RefreshRequested => {
 5227                (InvalidationStrategy::RefreshRequested, None)
 5228            }
 5229        };
 5230
 5231        if let Some(InlaySplice {
 5232            to_remove,
 5233            to_insert,
 5234        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5235            reason_description,
 5236            self.visible_excerpts(required_languages.as_ref(), cx),
 5237            invalidate_cache,
 5238            ignore_debounce,
 5239            cx,
 5240        ) {
 5241            self.splice_inlays(&to_remove, to_insert, cx);
 5242        }
 5243    }
 5244
 5245    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5246        self.display_map
 5247            .read(cx)
 5248            .current_inlays()
 5249            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5250            .cloned()
 5251            .collect()
 5252    }
 5253
 5254    pub fn visible_excerpts(
 5255        &self,
 5256        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5257        cx: &mut Context<Editor>,
 5258    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5259        let Some(project) = self.project() else {
 5260            return HashMap::default();
 5261        };
 5262        let project = project.read(cx);
 5263        let multi_buffer = self.buffer().read(cx);
 5264        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5265        let multi_buffer_visible_start = self
 5266            .scroll_manager
 5267            .anchor()
 5268            .anchor
 5269            .to_point(&multi_buffer_snapshot);
 5270        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5271            multi_buffer_visible_start
 5272                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5273            Bias::Left,
 5274        );
 5275        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5276        multi_buffer_snapshot
 5277            .range_to_buffer_ranges(multi_buffer_visible_range)
 5278            .into_iter()
 5279            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5280            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5281                let buffer_file = project::File::from_dyn(buffer.file())?;
 5282                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5283                let worktree_entry = buffer_worktree
 5284                    .read(cx)
 5285                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5286                if worktree_entry.is_ignored {
 5287                    return None;
 5288                }
 5289
 5290                let language = buffer.language()?;
 5291                if let Some(restrict_to_languages) = restrict_to_languages
 5292                    && !restrict_to_languages.contains(language)
 5293                {
 5294                    return None;
 5295                }
 5296                Some((
 5297                    excerpt_id,
 5298                    (
 5299                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5300                        buffer.version().clone(),
 5301                        excerpt_visible_range,
 5302                    ),
 5303                ))
 5304            })
 5305            .collect()
 5306    }
 5307
 5308    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5309        TextLayoutDetails {
 5310            text_system: window.text_system().clone(),
 5311            editor_style: self.style.clone().unwrap(),
 5312            rem_size: window.rem_size(),
 5313            scroll_anchor: self.scroll_manager.anchor(),
 5314            visible_rows: self.visible_line_count(),
 5315            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5316        }
 5317    }
 5318
 5319    pub fn splice_inlays(
 5320        &self,
 5321        to_remove: &[InlayId],
 5322        to_insert: Vec<Inlay>,
 5323        cx: &mut Context<Self>,
 5324    ) {
 5325        self.display_map.update(cx, |display_map, cx| {
 5326            display_map.splice_inlays(to_remove, to_insert, cx)
 5327        });
 5328        cx.notify();
 5329    }
 5330
 5331    fn trigger_on_type_formatting(
 5332        &self,
 5333        input: String,
 5334        window: &mut Window,
 5335        cx: &mut Context<Self>,
 5336    ) -> Option<Task<Result<()>>> {
 5337        if input.len() != 1 {
 5338            return None;
 5339        }
 5340
 5341        let project = self.project()?;
 5342        let position = self.selections.newest_anchor().head();
 5343        let (buffer, buffer_position) = self
 5344            .buffer
 5345            .read(cx)
 5346            .text_anchor_for_position(position, cx)?;
 5347
 5348        let settings = language_settings::language_settings(
 5349            buffer
 5350                .read(cx)
 5351                .language_at(buffer_position)
 5352                .map(|l| l.name()),
 5353            buffer.read(cx).file(),
 5354            cx,
 5355        );
 5356        if !settings.use_on_type_format {
 5357            return None;
 5358        }
 5359
 5360        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5361        // hence we do LSP request & edit on host side only — add formats to host's history.
 5362        let push_to_lsp_host_history = true;
 5363        // If this is not the host, append its history with new edits.
 5364        let push_to_client_history = project.read(cx).is_via_collab();
 5365
 5366        let on_type_formatting = project.update(cx, |project, cx| {
 5367            project.on_type_format(
 5368                buffer.clone(),
 5369                buffer_position,
 5370                input,
 5371                push_to_lsp_host_history,
 5372                cx,
 5373            )
 5374        });
 5375        Some(cx.spawn_in(window, async move |editor, cx| {
 5376            if let Some(transaction) = on_type_formatting.await? {
 5377                if push_to_client_history {
 5378                    buffer
 5379                        .update(cx, |buffer, _| {
 5380                            buffer.push_transaction(transaction, Instant::now());
 5381                            buffer.finalize_last_transaction();
 5382                        })
 5383                        .ok();
 5384                }
 5385                editor.update(cx, |editor, cx| {
 5386                    editor.refresh_document_highlights(cx);
 5387                })?;
 5388            }
 5389            Ok(())
 5390        }))
 5391    }
 5392
 5393    pub fn show_word_completions(
 5394        &mut self,
 5395        _: &ShowWordCompletions,
 5396        window: &mut Window,
 5397        cx: &mut Context<Self>,
 5398    ) {
 5399        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5400    }
 5401
 5402    pub fn show_completions(
 5403        &mut self,
 5404        options: &ShowCompletions,
 5405        window: &mut Window,
 5406        cx: &mut Context<Self>,
 5407    ) {
 5408        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5409    }
 5410
 5411    fn open_or_update_completions_menu(
 5412        &mut self,
 5413        requested_source: Option<CompletionsMenuSource>,
 5414        trigger: Option<&str>,
 5415        window: &mut Window,
 5416        cx: &mut Context<Self>,
 5417    ) {
 5418        if self.pending_rename.is_some() {
 5419            return;
 5420        }
 5421
 5422        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5423
 5424        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5425        // inserted and selected. To handle that case, the start of the selection is used so that
 5426        // the menu starts with all choices.
 5427        let position = self
 5428            .selections
 5429            .newest_anchor()
 5430            .start
 5431            .bias_right(&multibuffer_snapshot);
 5432        if position.diff_base_anchor.is_some() {
 5433            return;
 5434        }
 5435        let (buffer, buffer_position) =
 5436            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5437                output
 5438            } else {
 5439                return;
 5440            };
 5441        let buffer_snapshot = buffer.read(cx).snapshot();
 5442
 5443        let query: Option<Arc<String>> =
 5444            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5445
 5446        drop(multibuffer_snapshot);
 5447
 5448        let provider = match requested_source {
 5449            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5450            Some(CompletionsMenuSource::Words) => None,
 5451            Some(CompletionsMenuSource::SnippetChoices) => {
 5452                log::error!("bug: SnippetChoices requested_source is not handled");
 5453                None
 5454            }
 5455        };
 5456
 5457        let sort_completions = provider
 5458            .as_ref()
 5459            .is_some_and(|provider| provider.sort_completions());
 5460
 5461        let filter_completions = provider
 5462            .as_ref()
 5463            .is_none_or(|provider| provider.filter_completions());
 5464
 5465        let trigger_kind = match trigger {
 5466            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5467                CompletionTriggerKind::TRIGGER_CHARACTER
 5468            }
 5469            _ => CompletionTriggerKind::INVOKED,
 5470        };
 5471        let completion_context = CompletionContext {
 5472            trigger_character: trigger.and_then(|trigger| {
 5473                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5474                    Some(String::from(trigger))
 5475                } else {
 5476                    None
 5477                }
 5478            }),
 5479            trigger_kind,
 5480        };
 5481
 5482        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5483        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5484        // involve trigger chars, so this is skipped in that case.
 5485        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5486        {
 5487            let menu_is_open = matches!(
 5488                self.context_menu.borrow().as_ref(),
 5489                Some(CodeContextMenu::Completions(_))
 5490            );
 5491            if menu_is_open {
 5492                self.hide_context_menu(window, cx);
 5493            }
 5494        }
 5495
 5496        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5497            if filter_completions {
 5498                menu.filter(query.clone(), provider.clone(), window, cx);
 5499            }
 5500            // When `is_incomplete` is false, no need to re-query completions when the current query
 5501            // is a suffix of the initial query.
 5502            if !menu.is_incomplete {
 5503                // If the new query is a suffix of the old query (typing more characters) and
 5504                // the previous result was complete, the existing completions can be filtered.
 5505                //
 5506                // Note that this is always true for snippet completions.
 5507                let query_matches = match (&menu.initial_query, &query) {
 5508                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5509                    (None, _) => true,
 5510                    _ => false,
 5511                };
 5512                if query_matches {
 5513                    let position_matches = if menu.initial_position == position {
 5514                        true
 5515                    } else {
 5516                        let snapshot = self.buffer.read(cx).read(cx);
 5517                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5518                    };
 5519                    if position_matches {
 5520                        return;
 5521                    }
 5522                }
 5523            }
 5524        };
 5525
 5526        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5527            buffer_snapshot.surrounding_word(buffer_position, false)
 5528        {
 5529            let word_to_exclude = buffer_snapshot
 5530                .text_for_range(word_range.clone())
 5531                .collect::<String>();
 5532            (
 5533                buffer_snapshot.anchor_before(word_range.start)
 5534                    ..buffer_snapshot.anchor_after(buffer_position),
 5535                Some(word_to_exclude),
 5536            )
 5537        } else {
 5538            (buffer_position..buffer_position, None)
 5539        };
 5540
 5541        let language = buffer_snapshot
 5542            .language_at(buffer_position)
 5543            .map(|language| language.name());
 5544
 5545        let completion_settings =
 5546            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5547
 5548        let show_completion_documentation = buffer_snapshot
 5549            .settings_at(buffer_position, cx)
 5550            .show_completion_documentation;
 5551
 5552        // The document can be large, so stay in reasonable bounds when searching for words,
 5553        // otherwise completion pop-up might be slow to appear.
 5554        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5555        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5556        let min_word_search = buffer_snapshot.clip_point(
 5557            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5558            Bias::Left,
 5559        );
 5560        let max_word_search = buffer_snapshot.clip_point(
 5561            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5562            Bias::Right,
 5563        );
 5564        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5565            ..buffer_snapshot.point_to_offset(max_word_search);
 5566
 5567        let skip_digits = query
 5568            .as_ref()
 5569            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5570
 5571        let (mut words, provider_responses) = match &provider {
 5572            Some(provider) => {
 5573                let provider_responses = provider.completions(
 5574                    position.excerpt_id,
 5575                    &buffer,
 5576                    buffer_position,
 5577                    completion_context,
 5578                    window,
 5579                    cx,
 5580                );
 5581
 5582                let words = match completion_settings.words {
 5583                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5584                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5585                        .background_spawn(async move {
 5586                            buffer_snapshot.words_in_range(WordsQuery {
 5587                                fuzzy_contents: None,
 5588                                range: word_search_range,
 5589                                skip_digits,
 5590                            })
 5591                        }),
 5592                };
 5593
 5594                (words, provider_responses)
 5595            }
 5596            None => (
 5597                cx.background_spawn(async move {
 5598                    buffer_snapshot.words_in_range(WordsQuery {
 5599                        fuzzy_contents: None,
 5600                        range: word_search_range,
 5601                        skip_digits,
 5602                    })
 5603                }),
 5604                Task::ready(Ok(Vec::new())),
 5605            ),
 5606        };
 5607
 5608        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5609
 5610        let id = post_inc(&mut self.next_completion_id);
 5611        let task = cx.spawn_in(window, async move |editor, cx| {
 5612            let Ok(()) = editor.update(cx, |this, _| {
 5613                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5614            }) else {
 5615                return;
 5616            };
 5617
 5618            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5619            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5620            let mut completions = Vec::new();
 5621            let mut is_incomplete = false;
 5622            if let Some(provider_responses) = provider_responses.await.log_err()
 5623                && !provider_responses.is_empty()
 5624            {
 5625                for response in provider_responses {
 5626                    completions.extend(response.completions);
 5627                    is_incomplete = is_incomplete || response.is_incomplete;
 5628                }
 5629                if completion_settings.words == WordsCompletionMode::Fallback {
 5630                    words = Task::ready(BTreeMap::default());
 5631                }
 5632            }
 5633
 5634            let mut words = words.await;
 5635            if let Some(word_to_exclude) = &word_to_exclude {
 5636                words.remove(word_to_exclude);
 5637            }
 5638            for lsp_completion in &completions {
 5639                words.remove(&lsp_completion.new_text);
 5640            }
 5641            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5642                replace_range: word_replace_range.clone(),
 5643                new_text: word.clone(),
 5644                label: CodeLabel::plain(word, None),
 5645                icon_path: None,
 5646                documentation: None,
 5647                source: CompletionSource::BufferWord {
 5648                    word_range,
 5649                    resolved: false,
 5650                },
 5651                insert_text_mode: Some(InsertTextMode::AS_IS),
 5652                confirm: None,
 5653            }));
 5654
 5655            let menu = if completions.is_empty() {
 5656                None
 5657            } else {
 5658                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5659                    let languages = editor
 5660                        .workspace
 5661                        .as_ref()
 5662                        .and_then(|(workspace, _)| workspace.upgrade())
 5663                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5664                    let menu = CompletionsMenu::new(
 5665                        id,
 5666                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5667                        sort_completions,
 5668                        show_completion_documentation,
 5669                        position,
 5670                        query.clone(),
 5671                        is_incomplete,
 5672                        buffer.clone(),
 5673                        completions.into(),
 5674                        snippet_sort_order,
 5675                        languages,
 5676                        language,
 5677                        cx,
 5678                    );
 5679
 5680                    let query = if filter_completions { query } else { None };
 5681                    let matches_task = if let Some(query) = query {
 5682                        menu.do_async_filtering(query, cx)
 5683                    } else {
 5684                        Task::ready(menu.unfiltered_matches())
 5685                    };
 5686                    (menu, matches_task)
 5687                }) else {
 5688                    return;
 5689                };
 5690
 5691                let matches = matches_task.await;
 5692
 5693                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5694                    // Newer menu already set, so exit.
 5695                    match editor.context_menu.borrow().as_ref() {
 5696                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5697                            if prev_menu.id > id {
 5698                                return;
 5699                            }
 5700                        }
 5701                        _ => {}
 5702                    };
 5703
 5704                    // Only valid to take prev_menu because it the new menu is immediately set
 5705                    // below, or the menu is hidden.
 5706                    match editor.context_menu.borrow_mut().take() {
 5707                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5708                            let position_matches =
 5709                                if prev_menu.initial_position == menu.initial_position {
 5710                                    true
 5711                                } else {
 5712                                    let snapshot = editor.buffer.read(cx).read(cx);
 5713                                    prev_menu.initial_position.to_offset(&snapshot)
 5714                                        == menu.initial_position.to_offset(&snapshot)
 5715                                };
 5716                            if position_matches {
 5717                                // Preserve markdown cache before `set_filter_results` because it will
 5718                                // try to populate the documentation cache.
 5719                                menu.preserve_markdown_cache(prev_menu);
 5720                            }
 5721                        }
 5722                        _ => {}
 5723                    };
 5724
 5725                    menu.set_filter_results(matches, provider, window, cx);
 5726                }) else {
 5727                    return;
 5728                };
 5729
 5730                menu.visible().then_some(menu)
 5731            };
 5732
 5733            editor
 5734                .update_in(cx, |editor, window, cx| {
 5735                    if editor.focus_handle.is_focused(window)
 5736                        && let Some(menu) = menu
 5737                    {
 5738                        *editor.context_menu.borrow_mut() =
 5739                            Some(CodeContextMenu::Completions(menu));
 5740
 5741                        crate::hover_popover::hide_hover(editor, cx);
 5742                        if editor.show_edit_predictions_in_menu() {
 5743                            editor.update_visible_edit_prediction(window, cx);
 5744                        } else {
 5745                            editor.discard_edit_prediction(false, cx);
 5746                        }
 5747
 5748                        cx.notify();
 5749                        return;
 5750                    }
 5751
 5752                    if editor.completion_tasks.len() <= 1 {
 5753                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5754                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5755                        // If it was already hidden and we don't show edit predictions in the menu,
 5756                        // we should also show the edit prediction when available.
 5757                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5758                            editor.update_visible_edit_prediction(window, cx);
 5759                        }
 5760                    }
 5761                })
 5762                .ok();
 5763        });
 5764
 5765        self.completion_tasks.push((id, task));
 5766    }
 5767
 5768    #[cfg(feature = "test-support")]
 5769    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5770        let menu = self.context_menu.borrow();
 5771        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5772            let completions = menu.completions.borrow();
 5773            Some(completions.to_vec())
 5774        } else {
 5775            None
 5776        }
 5777    }
 5778
 5779    pub fn with_completions_menu_matching_id<R>(
 5780        &self,
 5781        id: CompletionId,
 5782        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5783    ) -> R {
 5784        let mut context_menu = self.context_menu.borrow_mut();
 5785        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5786            return f(None);
 5787        };
 5788        if completions_menu.id != id {
 5789            return f(None);
 5790        }
 5791        f(Some(completions_menu))
 5792    }
 5793
 5794    pub fn confirm_completion(
 5795        &mut self,
 5796        action: &ConfirmCompletion,
 5797        window: &mut Window,
 5798        cx: &mut Context<Self>,
 5799    ) -> Option<Task<Result<()>>> {
 5800        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5801        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5802    }
 5803
 5804    pub fn confirm_completion_insert(
 5805        &mut self,
 5806        _: &ConfirmCompletionInsert,
 5807        window: &mut Window,
 5808        cx: &mut Context<Self>,
 5809    ) -> Option<Task<Result<()>>> {
 5810        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5811        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5812    }
 5813
 5814    pub fn confirm_completion_replace(
 5815        &mut self,
 5816        _: &ConfirmCompletionReplace,
 5817        window: &mut Window,
 5818        cx: &mut Context<Self>,
 5819    ) -> Option<Task<Result<()>>> {
 5820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5821        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5822    }
 5823
 5824    pub fn compose_completion(
 5825        &mut self,
 5826        action: &ComposeCompletion,
 5827        window: &mut Window,
 5828        cx: &mut Context<Self>,
 5829    ) -> Option<Task<Result<()>>> {
 5830        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5831        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5832    }
 5833
 5834    fn do_completion(
 5835        &mut self,
 5836        item_ix: Option<usize>,
 5837        intent: CompletionIntent,
 5838        window: &mut Window,
 5839        cx: &mut Context<Editor>,
 5840    ) -> Option<Task<Result<()>>> {
 5841        use language::ToOffset as _;
 5842
 5843        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5844        else {
 5845            return None;
 5846        };
 5847
 5848        let candidate_id = {
 5849            let entries = completions_menu.entries.borrow();
 5850            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5851            if self.show_edit_predictions_in_menu() {
 5852                self.discard_edit_prediction(true, cx);
 5853            }
 5854            mat.candidate_id
 5855        };
 5856
 5857        let completion = completions_menu
 5858            .completions
 5859            .borrow()
 5860            .get(candidate_id)?
 5861            .clone();
 5862        cx.stop_propagation();
 5863
 5864        let buffer_handle = completions_menu.buffer.clone();
 5865
 5866        let CompletionEdit {
 5867            new_text,
 5868            snippet,
 5869            replace_range,
 5870        } = process_completion_for_edit(
 5871            &completion,
 5872            intent,
 5873            &buffer_handle,
 5874            &completions_menu.initial_position.text_anchor,
 5875            cx,
 5876        );
 5877
 5878        let buffer = buffer_handle.read(cx);
 5879        let snapshot = self.buffer.read(cx).snapshot(cx);
 5880        let newest_anchor = self.selections.newest_anchor();
 5881        let replace_range_multibuffer = {
 5882            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5883            let multibuffer_anchor = snapshot
 5884                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5885                .unwrap()
 5886                ..snapshot
 5887                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5888                    .unwrap();
 5889            multibuffer_anchor.start.to_offset(&snapshot)
 5890                ..multibuffer_anchor.end.to_offset(&snapshot)
 5891        };
 5892        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5893            return None;
 5894        }
 5895
 5896        let old_text = buffer
 5897            .text_for_range(replace_range.clone())
 5898            .collect::<String>();
 5899        let lookbehind = newest_anchor
 5900            .start
 5901            .text_anchor
 5902            .to_offset(buffer)
 5903            .saturating_sub(replace_range.start);
 5904        let lookahead = replace_range
 5905            .end
 5906            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5907        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5908        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5909
 5910        let selections = self.selections.all::<usize>(cx);
 5911        let mut ranges = Vec::new();
 5912        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5913
 5914        for selection in &selections {
 5915            let range = if selection.id == newest_anchor.id {
 5916                replace_range_multibuffer.clone()
 5917            } else {
 5918                let mut range = selection.range();
 5919
 5920                // if prefix is present, don't duplicate it
 5921                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5922                    range.start = range.start.saturating_sub(lookbehind);
 5923
 5924                    // if suffix is also present, mimic the newest cursor and replace it
 5925                    if selection.id != newest_anchor.id
 5926                        && snapshot.contains_str_at(range.end, suffix)
 5927                    {
 5928                        range.end += lookahead;
 5929                    }
 5930                }
 5931                range
 5932            };
 5933
 5934            ranges.push(range.clone());
 5935
 5936            if !self.linked_edit_ranges.is_empty() {
 5937                let start_anchor = snapshot.anchor_before(range.start);
 5938                let end_anchor = snapshot.anchor_after(range.end);
 5939                if let Some(ranges) = self
 5940                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5941                {
 5942                    for (buffer, edits) in ranges {
 5943                        linked_edits
 5944                            .entry(buffer.clone())
 5945                            .or_default()
 5946                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5947                    }
 5948                }
 5949            }
 5950        }
 5951
 5952        let common_prefix_len = old_text
 5953            .chars()
 5954            .zip(new_text.chars())
 5955            .take_while(|(a, b)| a == b)
 5956            .map(|(a, _)| a.len_utf8())
 5957            .sum::<usize>();
 5958
 5959        cx.emit(EditorEvent::InputHandled {
 5960            utf16_range_to_replace: None,
 5961            text: new_text[common_prefix_len..].into(),
 5962        });
 5963
 5964        self.transact(window, cx, |editor, window, cx| {
 5965            if let Some(mut snippet) = snippet {
 5966                snippet.text = new_text.to_string();
 5967                editor
 5968                    .insert_snippet(&ranges, snippet, window, cx)
 5969                    .log_err();
 5970            } else {
 5971                editor.buffer.update(cx, |multi_buffer, cx| {
 5972                    let auto_indent = match completion.insert_text_mode {
 5973                        Some(InsertTextMode::AS_IS) => None,
 5974                        _ => editor.autoindent_mode.clone(),
 5975                    };
 5976                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5977                    multi_buffer.edit(edits, auto_indent, cx);
 5978                });
 5979            }
 5980            for (buffer, edits) in linked_edits {
 5981                buffer.update(cx, |buffer, cx| {
 5982                    let snapshot = buffer.snapshot();
 5983                    let edits = edits
 5984                        .into_iter()
 5985                        .map(|(range, text)| {
 5986                            use text::ToPoint as TP;
 5987                            let end_point = TP::to_point(&range.end, &snapshot);
 5988                            let start_point = TP::to_point(&range.start, &snapshot);
 5989                            (start_point..end_point, text)
 5990                        })
 5991                        .sorted_by_key(|(range, _)| range.start);
 5992                    buffer.edit(edits, None, cx);
 5993                })
 5994            }
 5995
 5996            editor.refresh_edit_prediction(true, false, window, cx);
 5997        });
 5998        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5999
 6000        let show_new_completions_on_confirm = completion
 6001            .confirm
 6002            .as_ref()
 6003            .is_some_and(|confirm| confirm(intent, window, cx));
 6004        if show_new_completions_on_confirm {
 6005            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6006        }
 6007
 6008        let provider = self.completion_provider.as_ref()?;
 6009        drop(completion);
 6010        let apply_edits = provider.apply_additional_edits_for_completion(
 6011            buffer_handle,
 6012            completions_menu.completions.clone(),
 6013            candidate_id,
 6014            true,
 6015            cx,
 6016        );
 6017
 6018        let editor_settings = EditorSettings::get_global(cx);
 6019        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6020            // After the code completion is finished, users often want to know what signatures are needed.
 6021            // so we should automatically call signature_help
 6022            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6023        }
 6024
 6025        Some(cx.foreground_executor().spawn(async move {
 6026            apply_edits.await?;
 6027            Ok(())
 6028        }))
 6029    }
 6030
 6031    pub fn toggle_code_actions(
 6032        &mut self,
 6033        action: &ToggleCodeActions,
 6034        window: &mut Window,
 6035        cx: &mut Context<Self>,
 6036    ) {
 6037        let quick_launch = action.quick_launch;
 6038        let mut context_menu = self.context_menu.borrow_mut();
 6039        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6040            if code_actions.deployed_from == action.deployed_from {
 6041                // Toggle if we're selecting the same one
 6042                *context_menu = None;
 6043                cx.notify();
 6044                return;
 6045            } else {
 6046                // Otherwise, clear it and start a new one
 6047                *context_menu = None;
 6048                cx.notify();
 6049            }
 6050        }
 6051        drop(context_menu);
 6052        let snapshot = self.snapshot(window, cx);
 6053        let deployed_from = action.deployed_from.clone();
 6054        let action = action.clone();
 6055        self.completion_tasks.clear();
 6056        self.discard_edit_prediction(false, cx);
 6057
 6058        let multibuffer_point = match &action.deployed_from {
 6059            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6060                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6061            }
 6062            _ => self.selections.newest::<Point>(cx).head(),
 6063        };
 6064        let Some((buffer, buffer_row)) = snapshot
 6065            .buffer_snapshot
 6066            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6067            .and_then(|(buffer_snapshot, range)| {
 6068                self.buffer()
 6069                    .read(cx)
 6070                    .buffer(buffer_snapshot.remote_id())
 6071                    .map(|buffer| (buffer, range.start.row))
 6072            })
 6073        else {
 6074            return;
 6075        };
 6076        let buffer_id = buffer.read(cx).remote_id();
 6077        let tasks = self
 6078            .tasks
 6079            .get(&(buffer_id, buffer_row))
 6080            .map(|t| Arc::new(t.to_owned()));
 6081
 6082        if !self.focus_handle.is_focused(window) {
 6083            return;
 6084        }
 6085        let project = self.project.clone();
 6086
 6087        let code_actions_task = match deployed_from {
 6088            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6089            _ => self.code_actions(buffer_row, window, cx),
 6090        };
 6091
 6092        let runnable_task = match deployed_from {
 6093            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6094            _ => {
 6095                let mut task_context_task = Task::ready(None);
 6096                if let Some(tasks) = &tasks
 6097                    && let Some(project) = project
 6098                {
 6099                    task_context_task =
 6100                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6101                }
 6102
 6103                cx.spawn_in(window, {
 6104                    let buffer = buffer.clone();
 6105                    async move |editor, cx| {
 6106                        let task_context = task_context_task.await;
 6107
 6108                        let resolved_tasks =
 6109                            tasks
 6110                                .zip(task_context.clone())
 6111                                .map(|(tasks, task_context)| ResolvedTasks {
 6112                                    templates: tasks.resolve(&task_context).collect(),
 6113                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6114                                        multibuffer_point.row,
 6115                                        tasks.column,
 6116                                    )),
 6117                                });
 6118                        let debug_scenarios = editor
 6119                            .update(cx, |editor, cx| {
 6120                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6121                            })?
 6122                            .await;
 6123                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6124                    }
 6125                })
 6126            }
 6127        };
 6128
 6129        cx.spawn_in(window, async move |editor, cx| {
 6130            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6131            let code_actions = code_actions_task.await;
 6132            let spawn_straight_away = quick_launch
 6133                && resolved_tasks
 6134                    .as_ref()
 6135                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6136                && code_actions
 6137                    .as_ref()
 6138                    .is_none_or(|actions| actions.is_empty())
 6139                && debug_scenarios.is_empty();
 6140
 6141            editor.update_in(cx, |editor, window, cx| {
 6142                crate::hover_popover::hide_hover(editor, cx);
 6143                let actions = CodeActionContents::new(
 6144                    resolved_tasks,
 6145                    code_actions,
 6146                    debug_scenarios,
 6147                    task_context.unwrap_or_default(),
 6148                );
 6149
 6150                // Don't show the menu if there are no actions available
 6151                if actions.is_empty() {
 6152                    cx.notify();
 6153                    return Task::ready(Ok(()));
 6154                }
 6155
 6156                *editor.context_menu.borrow_mut() =
 6157                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6158                        buffer,
 6159                        actions,
 6160                        selected_item: Default::default(),
 6161                        scroll_handle: UniformListScrollHandle::default(),
 6162                        deployed_from,
 6163                    }));
 6164                cx.notify();
 6165                if spawn_straight_away
 6166                    && let Some(task) = editor.confirm_code_action(
 6167                        &ConfirmCodeAction { item_ix: Some(0) },
 6168                        window,
 6169                        cx,
 6170                    )
 6171                {
 6172                    return task;
 6173                }
 6174
 6175                Task::ready(Ok(()))
 6176            })
 6177        })
 6178        .detach_and_log_err(cx);
 6179    }
 6180
 6181    fn debug_scenarios(
 6182        &mut self,
 6183        resolved_tasks: &Option<ResolvedTasks>,
 6184        buffer: &Entity<Buffer>,
 6185        cx: &mut App,
 6186    ) -> Task<Vec<task::DebugScenario>> {
 6187        maybe!({
 6188            let project = self.project()?;
 6189            let dap_store = project.read(cx).dap_store();
 6190            let mut scenarios = vec![];
 6191            let resolved_tasks = resolved_tasks.as_ref()?;
 6192            let buffer = buffer.read(cx);
 6193            let language = buffer.language()?;
 6194            let file = buffer.file();
 6195            let debug_adapter = language_settings(language.name().into(), file, cx)
 6196                .debuggers
 6197                .first()
 6198                .map(SharedString::from)
 6199                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6200
 6201            dap_store.update(cx, |dap_store, cx| {
 6202                for (_, task) in &resolved_tasks.templates {
 6203                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6204                        task.original_task().clone(),
 6205                        debug_adapter.clone().into(),
 6206                        task.display_label().to_owned().into(),
 6207                        cx,
 6208                    );
 6209                    scenarios.push(maybe_scenario);
 6210                }
 6211            });
 6212            Some(cx.background_spawn(async move {
 6213                let scenarios = futures::future::join_all(scenarios)
 6214                    .await
 6215                    .into_iter()
 6216                    .flatten()
 6217                    .collect::<Vec<_>>();
 6218                scenarios
 6219            }))
 6220        })
 6221        .unwrap_or_else(|| Task::ready(vec![]))
 6222    }
 6223
 6224    fn code_actions(
 6225        &mut self,
 6226        buffer_row: u32,
 6227        window: &mut Window,
 6228        cx: &mut Context<Self>,
 6229    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6230        let mut task = self.code_actions_task.take();
 6231        cx.spawn_in(window, async move |editor, cx| {
 6232            while let Some(prev_task) = task {
 6233                prev_task.await.log_err();
 6234                task = editor
 6235                    .update(cx, |this, _| this.code_actions_task.take())
 6236                    .ok()?;
 6237            }
 6238
 6239            editor
 6240                .update(cx, |editor, cx| {
 6241                    editor
 6242                        .available_code_actions
 6243                        .clone()
 6244                        .and_then(|(location, code_actions)| {
 6245                            let snapshot = location.buffer.read(cx).snapshot();
 6246                            let point_range = location.range.to_point(&snapshot);
 6247                            let point_range = point_range.start.row..=point_range.end.row;
 6248                            if point_range.contains(&buffer_row) {
 6249                                Some(code_actions)
 6250                            } else {
 6251                                None
 6252                            }
 6253                        })
 6254                })
 6255                .ok()
 6256                .flatten()
 6257        })
 6258    }
 6259
 6260    pub fn confirm_code_action(
 6261        &mut self,
 6262        action: &ConfirmCodeAction,
 6263        window: &mut Window,
 6264        cx: &mut Context<Self>,
 6265    ) -> Option<Task<Result<()>>> {
 6266        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6267
 6268        let actions_menu =
 6269            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6270                menu
 6271            } else {
 6272                return None;
 6273            };
 6274
 6275        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6276        let action = actions_menu.actions.get(action_ix)?;
 6277        let title = action.label();
 6278        let buffer = actions_menu.buffer;
 6279        let workspace = self.workspace()?;
 6280
 6281        match action {
 6282            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6283                workspace.update(cx, |workspace, cx| {
 6284                    workspace.schedule_resolved_task(
 6285                        task_source_kind,
 6286                        resolved_task,
 6287                        false,
 6288                        window,
 6289                        cx,
 6290                    );
 6291
 6292                    Some(Task::ready(Ok(())))
 6293                })
 6294            }
 6295            CodeActionsItem::CodeAction {
 6296                excerpt_id,
 6297                action,
 6298                provider,
 6299            } => {
 6300                let apply_code_action =
 6301                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6302                let workspace = workspace.downgrade();
 6303                Some(cx.spawn_in(window, async move |editor, cx| {
 6304                    let project_transaction = apply_code_action.await?;
 6305                    Self::open_project_transaction(
 6306                        &editor,
 6307                        workspace,
 6308                        project_transaction,
 6309                        title,
 6310                        cx,
 6311                    )
 6312                    .await
 6313                }))
 6314            }
 6315            CodeActionsItem::DebugScenario(scenario) => {
 6316                let context = actions_menu.actions.context.clone();
 6317
 6318                workspace.update(cx, |workspace, cx| {
 6319                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6320                    workspace.start_debug_session(
 6321                        scenario,
 6322                        context,
 6323                        Some(buffer),
 6324                        None,
 6325                        window,
 6326                        cx,
 6327                    );
 6328                });
 6329                Some(Task::ready(Ok(())))
 6330            }
 6331        }
 6332    }
 6333
 6334    pub async fn open_project_transaction(
 6335        this: &WeakEntity<Editor>,
 6336        workspace: WeakEntity<Workspace>,
 6337        transaction: ProjectTransaction,
 6338        title: String,
 6339        cx: &mut AsyncWindowContext,
 6340    ) -> Result<()> {
 6341        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6342        cx.update(|_, cx| {
 6343            entries.sort_unstable_by_key(|(buffer, _)| {
 6344                buffer.read(cx).file().map(|f| f.path().clone())
 6345            });
 6346        })?;
 6347
 6348        // If the project transaction's edits are all contained within this editor, then
 6349        // avoid opening a new editor to display them.
 6350
 6351        if let Some((buffer, transaction)) = entries.first() {
 6352            if entries.len() == 1 {
 6353                let excerpt = this.update(cx, |editor, cx| {
 6354                    editor
 6355                        .buffer()
 6356                        .read(cx)
 6357                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6358                })?;
 6359                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6360                    && excerpted_buffer == *buffer
 6361                {
 6362                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6363                        let excerpt_range = excerpt_range.to_offset(buffer);
 6364                        buffer
 6365                            .edited_ranges_for_transaction::<usize>(transaction)
 6366                            .all(|range| {
 6367                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6368                            })
 6369                    })?;
 6370
 6371                    if all_edits_within_excerpt {
 6372                        return Ok(());
 6373                    }
 6374                }
 6375            }
 6376        } else {
 6377            return Ok(());
 6378        }
 6379
 6380        let mut ranges_to_highlight = Vec::new();
 6381        let excerpt_buffer = cx.new(|cx| {
 6382            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6383            for (buffer_handle, transaction) in &entries {
 6384                let edited_ranges = buffer_handle
 6385                    .read(cx)
 6386                    .edited_ranges_for_transaction::<Point>(transaction)
 6387                    .collect::<Vec<_>>();
 6388                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6389                    PathKey::for_buffer(buffer_handle, cx),
 6390                    buffer_handle.clone(),
 6391                    edited_ranges,
 6392                    DEFAULT_MULTIBUFFER_CONTEXT,
 6393                    cx,
 6394                );
 6395
 6396                ranges_to_highlight.extend(ranges);
 6397            }
 6398            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6399            multibuffer
 6400        })?;
 6401
 6402        workspace.update_in(cx, |workspace, window, cx| {
 6403            let project = workspace.project().clone();
 6404            let editor =
 6405                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6406            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6407            editor.update(cx, |editor, cx| {
 6408                editor.highlight_background::<Self>(
 6409                    &ranges_to_highlight,
 6410                    |theme| theme.colors().editor_highlighted_line_background,
 6411                    cx,
 6412                );
 6413            });
 6414        })?;
 6415
 6416        Ok(())
 6417    }
 6418
 6419    pub fn clear_code_action_providers(&mut self) {
 6420        self.code_action_providers.clear();
 6421        self.available_code_actions.take();
 6422    }
 6423
 6424    pub fn add_code_action_provider(
 6425        &mut self,
 6426        provider: Rc<dyn CodeActionProvider>,
 6427        window: &mut Window,
 6428        cx: &mut Context<Self>,
 6429    ) {
 6430        if self
 6431            .code_action_providers
 6432            .iter()
 6433            .any(|existing_provider| existing_provider.id() == provider.id())
 6434        {
 6435            return;
 6436        }
 6437
 6438        self.code_action_providers.push(provider);
 6439        self.refresh_code_actions(window, cx);
 6440    }
 6441
 6442    pub fn remove_code_action_provider(
 6443        &mut self,
 6444        id: Arc<str>,
 6445        window: &mut Window,
 6446        cx: &mut Context<Self>,
 6447    ) {
 6448        self.code_action_providers
 6449            .retain(|provider| provider.id() != id);
 6450        self.refresh_code_actions(window, cx);
 6451    }
 6452
 6453    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6454        !self.code_action_providers.is_empty()
 6455            && EditorSettings::get_global(cx).toolbar.code_actions
 6456    }
 6457
 6458    pub fn has_available_code_actions(&self) -> bool {
 6459        self.available_code_actions
 6460            .as_ref()
 6461            .is_some_and(|(_, actions)| !actions.is_empty())
 6462    }
 6463
 6464    fn render_inline_code_actions(
 6465        &self,
 6466        icon_size: ui::IconSize,
 6467        display_row: DisplayRow,
 6468        is_active: bool,
 6469        cx: &mut Context<Self>,
 6470    ) -> AnyElement {
 6471        let show_tooltip = !self.context_menu_visible();
 6472        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6473            .icon_size(icon_size)
 6474            .shape(ui::IconButtonShape::Square)
 6475            .icon_color(ui::Color::Hidden)
 6476            .toggle_state(is_active)
 6477            .when(show_tooltip, |this| {
 6478                this.tooltip({
 6479                    let focus_handle = self.focus_handle.clone();
 6480                    move |window, cx| {
 6481                        Tooltip::for_action_in(
 6482                            "Toggle Code Actions",
 6483                            &ToggleCodeActions {
 6484                                deployed_from: None,
 6485                                quick_launch: false,
 6486                            },
 6487                            &focus_handle,
 6488                            window,
 6489                            cx,
 6490                        )
 6491                    }
 6492                })
 6493            })
 6494            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6495                window.focus(&editor.focus_handle(cx));
 6496                editor.toggle_code_actions(
 6497                    &crate::actions::ToggleCodeActions {
 6498                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6499                            display_row,
 6500                        )),
 6501                        quick_launch: false,
 6502                    },
 6503                    window,
 6504                    cx,
 6505                );
 6506            }))
 6507            .into_any_element()
 6508    }
 6509
 6510    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6511        &self.context_menu
 6512    }
 6513
 6514    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6515        let newest_selection = self.selections.newest_anchor().clone();
 6516        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6517        let buffer = self.buffer.read(cx);
 6518        if newest_selection.head().diff_base_anchor.is_some() {
 6519            return None;
 6520        }
 6521        let (start_buffer, start) =
 6522            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6523        let (end_buffer, end) =
 6524            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6525        if start_buffer != end_buffer {
 6526            return None;
 6527        }
 6528
 6529        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6530            cx.background_executor()
 6531                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6532                .await;
 6533
 6534            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6535                let providers = this.code_action_providers.clone();
 6536                let tasks = this
 6537                    .code_action_providers
 6538                    .iter()
 6539                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6540                    .collect::<Vec<_>>();
 6541                (providers, tasks)
 6542            })?;
 6543
 6544            let mut actions = Vec::new();
 6545            for (provider, provider_actions) in
 6546                providers.into_iter().zip(future::join_all(tasks).await)
 6547            {
 6548                if let Some(provider_actions) = provider_actions.log_err() {
 6549                    actions.extend(provider_actions.into_iter().map(|action| {
 6550                        AvailableCodeAction {
 6551                            excerpt_id: newest_selection.start.excerpt_id,
 6552                            action,
 6553                            provider: provider.clone(),
 6554                        }
 6555                    }));
 6556                }
 6557            }
 6558
 6559            this.update(cx, |this, cx| {
 6560                this.available_code_actions = if actions.is_empty() {
 6561                    None
 6562                } else {
 6563                    Some((
 6564                        Location {
 6565                            buffer: start_buffer,
 6566                            range: start..end,
 6567                        },
 6568                        actions.into(),
 6569                    ))
 6570                };
 6571                cx.notify();
 6572            })
 6573        }));
 6574        None
 6575    }
 6576
 6577    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6578        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6579            self.show_git_blame_inline = false;
 6580
 6581            self.show_git_blame_inline_delay_task =
 6582                Some(cx.spawn_in(window, async move |this, cx| {
 6583                    cx.background_executor().timer(delay).await;
 6584
 6585                    this.update(cx, |this, cx| {
 6586                        this.show_git_blame_inline = true;
 6587                        cx.notify();
 6588                    })
 6589                    .log_err();
 6590                }));
 6591        }
 6592    }
 6593
 6594    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6595        let snapshot = self.snapshot(window, cx);
 6596        let cursor = self.selections.newest::<Point>(cx).head();
 6597        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6598        else {
 6599            return;
 6600        };
 6601
 6602        let Some(blame) = self.blame.as_ref() else {
 6603            return;
 6604        };
 6605
 6606        let row_info = RowInfo {
 6607            buffer_id: Some(buffer.remote_id()),
 6608            buffer_row: Some(point.row),
 6609            ..Default::default()
 6610        };
 6611        let Some(blame_entry) = blame
 6612            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6613            .flatten()
 6614        else {
 6615            return;
 6616        };
 6617
 6618        let anchor = self.selections.newest_anchor().head();
 6619        let position = self.to_pixel_point(anchor, &snapshot, window);
 6620        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6621            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6622        };
 6623    }
 6624
 6625    fn show_blame_popover(
 6626        &mut self,
 6627        blame_entry: &BlameEntry,
 6628        position: gpui::Point<Pixels>,
 6629        ignore_timeout: bool,
 6630        cx: &mut Context<Self>,
 6631    ) {
 6632        if let Some(state) = &mut self.inline_blame_popover {
 6633            state.hide_task.take();
 6634        } else {
 6635            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6636            let blame_entry = blame_entry.clone();
 6637            let show_task = cx.spawn(async move |editor, cx| {
 6638                if !ignore_timeout {
 6639                    cx.background_executor()
 6640                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6641                        .await;
 6642                }
 6643                editor
 6644                    .update(cx, |editor, cx| {
 6645                        editor.inline_blame_popover_show_task.take();
 6646                        let Some(blame) = editor.blame.as_ref() else {
 6647                            return;
 6648                        };
 6649                        let blame = blame.read(cx);
 6650                        let details = blame.details_for_entry(&blame_entry);
 6651                        let markdown = cx.new(|cx| {
 6652                            Markdown::new(
 6653                                details
 6654                                    .as_ref()
 6655                                    .map(|message| message.message.clone())
 6656                                    .unwrap_or_default(),
 6657                                None,
 6658                                None,
 6659                                cx,
 6660                            )
 6661                        });
 6662                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6663                            position,
 6664                            hide_task: None,
 6665                            popover_bounds: None,
 6666                            popover_state: InlineBlamePopoverState {
 6667                                scroll_handle: ScrollHandle::new(),
 6668                                commit_message: details,
 6669                                markdown,
 6670                            },
 6671                            keyboard_grace: ignore_timeout,
 6672                        });
 6673                        cx.notify();
 6674                    })
 6675                    .ok();
 6676            });
 6677            self.inline_blame_popover_show_task = Some(show_task);
 6678        }
 6679    }
 6680
 6681    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6682        self.inline_blame_popover_show_task.take();
 6683        if let Some(state) = &mut self.inline_blame_popover {
 6684            let hide_task = cx.spawn(async move |editor, cx| {
 6685                cx.background_executor()
 6686                    .timer(std::time::Duration::from_millis(100))
 6687                    .await;
 6688                editor
 6689                    .update(cx, |editor, cx| {
 6690                        editor.inline_blame_popover.take();
 6691                        cx.notify();
 6692                    })
 6693                    .ok();
 6694            });
 6695            state.hide_task = Some(hide_task);
 6696        }
 6697    }
 6698
 6699    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6700        if self.pending_rename.is_some() {
 6701            return None;
 6702        }
 6703
 6704        let provider = self.semantics_provider.clone()?;
 6705        let buffer = self.buffer.read(cx);
 6706        let newest_selection = self.selections.newest_anchor().clone();
 6707        let cursor_position = newest_selection.head();
 6708        let (cursor_buffer, cursor_buffer_position) =
 6709            buffer.text_anchor_for_position(cursor_position, cx)?;
 6710        let (tail_buffer, tail_buffer_position) =
 6711            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6712        if cursor_buffer != tail_buffer {
 6713            return None;
 6714        }
 6715
 6716        let snapshot = cursor_buffer.read(cx).snapshot();
 6717        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6718        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6719        if start_word_range != end_word_range {
 6720            self.document_highlights_task.take();
 6721            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6722            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6723            return None;
 6724        }
 6725
 6726        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6727        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6728            cx.background_executor()
 6729                .timer(Duration::from_millis(debounce))
 6730                .await;
 6731
 6732            let highlights = if let Some(highlights) = cx
 6733                .update(|cx| {
 6734                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6735                })
 6736                .ok()
 6737                .flatten()
 6738            {
 6739                highlights.await.log_err()
 6740            } else {
 6741                None
 6742            };
 6743
 6744            if let Some(highlights) = highlights {
 6745                this.update(cx, |this, cx| {
 6746                    if this.pending_rename.is_some() {
 6747                        return;
 6748                    }
 6749
 6750                    let buffer_id = cursor_position.buffer_id;
 6751                    let buffer = this.buffer.read(cx);
 6752                    if buffer
 6753                        .text_anchor_for_position(cursor_position, cx)
 6754                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6755                    {
 6756                        return;
 6757                    }
 6758
 6759                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6760                    let mut write_ranges = Vec::new();
 6761                    let mut read_ranges = Vec::new();
 6762                    for highlight in highlights {
 6763                        for (excerpt_id, excerpt_range) in
 6764                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6765                        {
 6766                            let start = highlight
 6767                                .range
 6768                                .start
 6769                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6770                            let end = highlight
 6771                                .range
 6772                                .end
 6773                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6774                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6775                                continue;
 6776                            }
 6777
 6778                            let range = Anchor {
 6779                                buffer_id,
 6780                                excerpt_id,
 6781                                text_anchor: start,
 6782                                diff_base_anchor: None,
 6783                            }..Anchor {
 6784                                buffer_id,
 6785                                excerpt_id,
 6786                                text_anchor: end,
 6787                                diff_base_anchor: None,
 6788                            };
 6789                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6790                                write_ranges.push(range);
 6791                            } else {
 6792                                read_ranges.push(range);
 6793                            }
 6794                        }
 6795                    }
 6796
 6797                    this.highlight_background::<DocumentHighlightRead>(
 6798                        &read_ranges,
 6799                        |theme| theme.colors().editor_document_highlight_read_background,
 6800                        cx,
 6801                    );
 6802                    this.highlight_background::<DocumentHighlightWrite>(
 6803                        &write_ranges,
 6804                        |theme| theme.colors().editor_document_highlight_write_background,
 6805                        cx,
 6806                    );
 6807                    cx.notify();
 6808                })
 6809                .log_err();
 6810            }
 6811        }));
 6812        None
 6813    }
 6814
 6815    fn prepare_highlight_query_from_selection(
 6816        &mut self,
 6817        cx: &mut Context<Editor>,
 6818    ) -> Option<(String, Range<Anchor>)> {
 6819        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6820            return None;
 6821        }
 6822        if !EditorSettings::get_global(cx).selection_highlight {
 6823            return None;
 6824        }
 6825        if self.selections.count() != 1 || self.selections.line_mode {
 6826            return None;
 6827        }
 6828        let selection = self.selections.newest::<Point>(cx);
 6829        if selection.is_empty() || selection.start.row != selection.end.row {
 6830            return None;
 6831        }
 6832        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6833        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6834        let query = multi_buffer_snapshot
 6835            .text_for_range(selection_anchor_range.clone())
 6836            .collect::<String>();
 6837        if query.trim().is_empty() {
 6838            return None;
 6839        }
 6840        Some((query, selection_anchor_range))
 6841    }
 6842
 6843    fn update_selection_occurrence_highlights(
 6844        &mut self,
 6845        query_text: String,
 6846        query_range: Range<Anchor>,
 6847        multi_buffer_range_to_query: Range<Point>,
 6848        use_debounce: bool,
 6849        window: &mut Window,
 6850        cx: &mut Context<Editor>,
 6851    ) -> Task<()> {
 6852        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6853        cx.spawn_in(window, async move |editor, cx| {
 6854            if use_debounce {
 6855                cx.background_executor()
 6856                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6857                    .await;
 6858            }
 6859            let match_task = cx.background_spawn(async move {
 6860                let buffer_ranges = multi_buffer_snapshot
 6861                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6862                    .into_iter()
 6863                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6864                let mut match_ranges = Vec::new();
 6865                let Ok(regex) = project::search::SearchQuery::text(
 6866                    query_text.clone(),
 6867                    false,
 6868                    false,
 6869                    false,
 6870                    Default::default(),
 6871                    Default::default(),
 6872                    false,
 6873                    None,
 6874                ) else {
 6875                    return Vec::default();
 6876                };
 6877                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6878                    match_ranges.extend(
 6879                        regex
 6880                            .search(buffer_snapshot, Some(search_range.clone()))
 6881                            .await
 6882                            .into_iter()
 6883                            .filter_map(|match_range| {
 6884                                let match_start = buffer_snapshot
 6885                                    .anchor_after(search_range.start + match_range.start);
 6886                                let match_end = buffer_snapshot
 6887                                    .anchor_before(search_range.start + match_range.end);
 6888                                let match_anchor_range = Anchor::range_in_buffer(
 6889                                    excerpt_id,
 6890                                    buffer_snapshot.remote_id(),
 6891                                    match_start..match_end,
 6892                                );
 6893                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6894                            }),
 6895                    );
 6896                }
 6897                match_ranges
 6898            });
 6899            let match_ranges = match_task.await;
 6900            editor
 6901                .update_in(cx, |editor, _, cx| {
 6902                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6903                    if !match_ranges.is_empty() {
 6904                        editor.highlight_background::<SelectedTextHighlight>(
 6905                            &match_ranges,
 6906                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6907                            cx,
 6908                        )
 6909                    }
 6910                })
 6911                .log_err();
 6912        })
 6913    }
 6914
 6915    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6916        struct NewlineFold;
 6917        let type_id = std::any::TypeId::of::<NewlineFold>();
 6918        if !self.mode.is_single_line() {
 6919            return;
 6920        }
 6921        let snapshot = self.snapshot(window, cx);
 6922        if snapshot.buffer_snapshot.max_point().row == 0 {
 6923            return;
 6924        }
 6925        let task = cx.background_spawn(async move {
 6926            let new_newlines = snapshot
 6927                .buffer_chars_at(0)
 6928                .filter_map(|(c, i)| {
 6929                    if c == '\n' {
 6930                        Some(
 6931                            snapshot.buffer_snapshot.anchor_after(i)
 6932                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6933                        )
 6934                    } else {
 6935                        None
 6936                    }
 6937                })
 6938                .collect::<Vec<_>>();
 6939            let existing_newlines = snapshot
 6940                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6941                .filter_map(|fold| {
 6942                    if fold.placeholder.type_tag == Some(type_id) {
 6943                        Some(fold.range.start..fold.range.end)
 6944                    } else {
 6945                        None
 6946                    }
 6947                })
 6948                .collect::<Vec<_>>();
 6949
 6950            (new_newlines, existing_newlines)
 6951        });
 6952        self.folding_newlines = cx.spawn(async move |this, cx| {
 6953            let (new_newlines, existing_newlines) = task.await;
 6954            if new_newlines == existing_newlines {
 6955                return;
 6956            }
 6957            let placeholder = FoldPlaceholder {
 6958                render: Arc::new(move |_, _, cx| {
 6959                    div()
 6960                        .bg(cx.theme().status().hint_background)
 6961                        .border_b_1()
 6962                        .size_full()
 6963                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6964                        .border_color(cx.theme().status().hint)
 6965                        .child("\\n")
 6966                        .into_any()
 6967                }),
 6968                constrain_width: false,
 6969                merge_adjacent: false,
 6970                type_tag: Some(type_id),
 6971            };
 6972            let creases = new_newlines
 6973                .into_iter()
 6974                .map(|range| Crease::simple(range, placeholder.clone()))
 6975                .collect();
 6976            this.update(cx, |this, cx| {
 6977                this.display_map.update(cx, |display_map, cx| {
 6978                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6979                    display_map.fold(creases, cx);
 6980                });
 6981            })
 6982            .ok();
 6983        });
 6984    }
 6985
 6986    fn refresh_selected_text_highlights(
 6987        &mut self,
 6988        on_buffer_edit: bool,
 6989        window: &mut Window,
 6990        cx: &mut Context<Editor>,
 6991    ) {
 6992        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6993        else {
 6994            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6995            self.quick_selection_highlight_task.take();
 6996            self.debounced_selection_highlight_task.take();
 6997            return;
 6998        };
 6999        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7000        if on_buffer_edit
 7001            || self
 7002                .quick_selection_highlight_task
 7003                .as_ref()
 7004                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7005        {
 7006            let multi_buffer_visible_start = self
 7007                .scroll_manager
 7008                .anchor()
 7009                .anchor
 7010                .to_point(&multi_buffer_snapshot);
 7011            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7012                multi_buffer_visible_start
 7013                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7014                Bias::Left,
 7015            );
 7016            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7017            self.quick_selection_highlight_task = Some((
 7018                query_range.clone(),
 7019                self.update_selection_occurrence_highlights(
 7020                    query_text.clone(),
 7021                    query_range.clone(),
 7022                    multi_buffer_visible_range,
 7023                    false,
 7024                    window,
 7025                    cx,
 7026                ),
 7027            ));
 7028        }
 7029        if on_buffer_edit
 7030            || self
 7031                .debounced_selection_highlight_task
 7032                .as_ref()
 7033                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7034        {
 7035            let multi_buffer_start = multi_buffer_snapshot
 7036                .anchor_before(0)
 7037                .to_point(&multi_buffer_snapshot);
 7038            let multi_buffer_end = multi_buffer_snapshot
 7039                .anchor_after(multi_buffer_snapshot.len())
 7040                .to_point(&multi_buffer_snapshot);
 7041            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7042            self.debounced_selection_highlight_task = Some((
 7043                query_range.clone(),
 7044                self.update_selection_occurrence_highlights(
 7045                    query_text,
 7046                    query_range,
 7047                    multi_buffer_full_range,
 7048                    true,
 7049                    window,
 7050                    cx,
 7051                ),
 7052            ));
 7053        }
 7054    }
 7055
 7056    pub fn refresh_edit_prediction(
 7057        &mut self,
 7058        debounce: bool,
 7059        user_requested: bool,
 7060        window: &mut Window,
 7061        cx: &mut Context<Self>,
 7062    ) -> Option<()> {
 7063        if DisableAiSettings::get_global(cx).disable_ai {
 7064            return None;
 7065        }
 7066
 7067        let provider = self.edit_prediction_provider()?;
 7068        let cursor = self.selections.newest_anchor().head();
 7069        let (buffer, cursor_buffer_position) =
 7070            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7071
 7072        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7073            self.discard_edit_prediction(false, cx);
 7074            return None;
 7075        }
 7076
 7077        if !user_requested
 7078            && (!self.should_show_edit_predictions()
 7079                || !self.is_focused(window)
 7080                || buffer.read(cx).is_empty())
 7081        {
 7082            self.discard_edit_prediction(false, cx);
 7083            return None;
 7084        }
 7085
 7086        self.update_visible_edit_prediction(window, cx);
 7087        provider.refresh(
 7088            self.project.clone(),
 7089            buffer,
 7090            cursor_buffer_position,
 7091            debounce,
 7092            cx,
 7093        );
 7094        Some(())
 7095    }
 7096
 7097    fn show_edit_predictions_in_menu(&self) -> bool {
 7098        match self.edit_prediction_settings {
 7099            EditPredictionSettings::Disabled => false,
 7100            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7101        }
 7102    }
 7103
 7104    pub fn edit_predictions_enabled(&self) -> bool {
 7105        match self.edit_prediction_settings {
 7106            EditPredictionSettings::Disabled => false,
 7107            EditPredictionSettings::Enabled { .. } => true,
 7108        }
 7109    }
 7110
 7111    fn edit_prediction_requires_modifier(&self) -> bool {
 7112        match self.edit_prediction_settings {
 7113            EditPredictionSettings::Disabled => false,
 7114            EditPredictionSettings::Enabled {
 7115                preview_requires_modifier,
 7116                ..
 7117            } => preview_requires_modifier,
 7118        }
 7119    }
 7120
 7121    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7122        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7123            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7124            self.discard_edit_prediction(false, cx);
 7125        } else {
 7126            let selection = self.selections.newest_anchor();
 7127            let cursor = selection.head();
 7128
 7129            if let Some((buffer, cursor_buffer_position)) =
 7130                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7131            {
 7132                self.edit_prediction_settings =
 7133                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7134            }
 7135        }
 7136    }
 7137
 7138    fn edit_prediction_settings_at_position(
 7139        &self,
 7140        buffer: &Entity<Buffer>,
 7141        buffer_position: language::Anchor,
 7142        cx: &App,
 7143    ) -> EditPredictionSettings {
 7144        if !self.mode.is_full()
 7145            || !self.show_edit_predictions_override.unwrap_or(true)
 7146            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7147        {
 7148            return EditPredictionSettings::Disabled;
 7149        }
 7150
 7151        let buffer = buffer.read(cx);
 7152
 7153        let file = buffer.file();
 7154
 7155        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7156            return EditPredictionSettings::Disabled;
 7157        };
 7158
 7159        let by_provider = matches!(
 7160            self.menu_edit_predictions_policy,
 7161            MenuEditPredictionsPolicy::ByProvider
 7162        );
 7163
 7164        let show_in_menu = by_provider
 7165            && self
 7166                .edit_prediction_provider
 7167                .as_ref()
 7168                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7169
 7170        let preview_requires_modifier =
 7171            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7172
 7173        EditPredictionSettings::Enabled {
 7174            show_in_menu,
 7175            preview_requires_modifier,
 7176        }
 7177    }
 7178
 7179    fn should_show_edit_predictions(&self) -> bool {
 7180        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7181    }
 7182
 7183    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7184        matches!(
 7185            self.edit_prediction_preview,
 7186            EditPredictionPreview::Active { .. }
 7187        )
 7188    }
 7189
 7190    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7191        let cursor = self.selections.newest_anchor().head();
 7192        if let Some((buffer, cursor_position)) =
 7193            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7194        {
 7195            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7196        } else {
 7197            false
 7198        }
 7199    }
 7200
 7201    pub fn supports_minimap(&self, cx: &App) -> bool {
 7202        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7203    }
 7204
 7205    fn edit_predictions_enabled_in_buffer(
 7206        &self,
 7207        buffer: &Entity<Buffer>,
 7208        buffer_position: language::Anchor,
 7209        cx: &App,
 7210    ) -> bool {
 7211        maybe!({
 7212            if self.read_only(cx) {
 7213                return Some(false);
 7214            }
 7215            let provider = self.edit_prediction_provider()?;
 7216            if !provider.is_enabled(buffer, buffer_position, cx) {
 7217                return Some(false);
 7218            }
 7219            let buffer = buffer.read(cx);
 7220            let Some(file) = buffer.file() else {
 7221                return Some(true);
 7222            };
 7223            let settings = all_language_settings(Some(file), cx);
 7224            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7225        })
 7226        .unwrap_or(false)
 7227    }
 7228
 7229    fn cycle_edit_prediction(
 7230        &mut self,
 7231        direction: Direction,
 7232        window: &mut Window,
 7233        cx: &mut Context<Self>,
 7234    ) -> Option<()> {
 7235        let provider = self.edit_prediction_provider()?;
 7236        let cursor = self.selections.newest_anchor().head();
 7237        let (buffer, cursor_buffer_position) =
 7238            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7239        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7240            return None;
 7241        }
 7242
 7243        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7244        self.update_visible_edit_prediction(window, cx);
 7245
 7246        Some(())
 7247    }
 7248
 7249    pub fn show_edit_prediction(
 7250        &mut self,
 7251        _: &ShowEditPrediction,
 7252        window: &mut Window,
 7253        cx: &mut Context<Self>,
 7254    ) {
 7255        if !self.has_active_edit_prediction() {
 7256            self.refresh_edit_prediction(false, true, window, cx);
 7257            return;
 7258        }
 7259
 7260        self.update_visible_edit_prediction(window, cx);
 7261    }
 7262
 7263    pub fn display_cursor_names(
 7264        &mut self,
 7265        _: &DisplayCursorNames,
 7266        window: &mut Window,
 7267        cx: &mut Context<Self>,
 7268    ) {
 7269        self.show_cursor_names(window, cx);
 7270    }
 7271
 7272    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7273        self.show_cursor_names = true;
 7274        cx.notify();
 7275        cx.spawn_in(window, async move |this, cx| {
 7276            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7277            this.update(cx, |this, cx| {
 7278                this.show_cursor_names = false;
 7279                cx.notify()
 7280            })
 7281            .ok()
 7282        })
 7283        .detach();
 7284    }
 7285
 7286    pub fn next_edit_prediction(
 7287        &mut self,
 7288        _: &NextEditPrediction,
 7289        window: &mut Window,
 7290        cx: &mut Context<Self>,
 7291    ) {
 7292        if self.has_active_edit_prediction() {
 7293            self.cycle_edit_prediction(Direction::Next, window, cx);
 7294        } else {
 7295            let is_copilot_disabled = self
 7296                .refresh_edit_prediction(false, true, window, cx)
 7297                .is_none();
 7298            if is_copilot_disabled {
 7299                cx.propagate();
 7300            }
 7301        }
 7302    }
 7303
 7304    pub fn previous_edit_prediction(
 7305        &mut self,
 7306        _: &PreviousEditPrediction,
 7307        window: &mut Window,
 7308        cx: &mut Context<Self>,
 7309    ) {
 7310        if self.has_active_edit_prediction() {
 7311            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7312        } else {
 7313            let is_copilot_disabled = self
 7314                .refresh_edit_prediction(false, true, window, cx)
 7315                .is_none();
 7316            if is_copilot_disabled {
 7317                cx.propagate();
 7318            }
 7319        }
 7320    }
 7321
 7322    pub fn accept_edit_prediction(
 7323        &mut self,
 7324        _: &AcceptEditPrediction,
 7325        window: &mut Window,
 7326        cx: &mut Context<Self>,
 7327    ) {
 7328        if self.show_edit_predictions_in_menu() {
 7329            self.hide_context_menu(window, cx);
 7330        }
 7331
 7332        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7333            return;
 7334        };
 7335
 7336        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7337
 7338        match &active_edit_prediction.completion {
 7339            EditPrediction::Move { target, .. } => {
 7340                let target = *target;
 7341
 7342                if let Some(position_map) = &self.last_position_map {
 7343                    if position_map
 7344                        .visible_row_range
 7345                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7346                        || !self.edit_prediction_requires_modifier()
 7347                    {
 7348                        self.unfold_ranges(&[target..target], true, false, cx);
 7349                        // Note that this is also done in vim's handler of the Tab action.
 7350                        self.change_selections(
 7351                            SelectionEffects::scroll(Autoscroll::newest()),
 7352                            window,
 7353                            cx,
 7354                            |selections| {
 7355                                selections.select_anchor_ranges([target..target]);
 7356                            },
 7357                        );
 7358                        self.clear_row_highlights::<EditPredictionPreview>();
 7359
 7360                        self.edit_prediction_preview
 7361                            .set_previous_scroll_position(None);
 7362                    } else {
 7363                        self.edit_prediction_preview
 7364                            .set_previous_scroll_position(Some(
 7365                                position_map.snapshot.scroll_anchor,
 7366                            ));
 7367
 7368                        self.highlight_rows::<EditPredictionPreview>(
 7369                            target..target,
 7370                            cx.theme().colors().editor_highlighted_line_background,
 7371                            RowHighlightOptions {
 7372                                autoscroll: true,
 7373                                ..Default::default()
 7374                            },
 7375                            cx,
 7376                        );
 7377                        self.request_autoscroll(Autoscroll::fit(), cx);
 7378                    }
 7379                }
 7380            }
 7381            EditPrediction::Edit { edits, .. } => {
 7382                if let Some(provider) = self.edit_prediction_provider() {
 7383                    provider.accept(cx);
 7384                }
 7385
 7386                // Store the transaction ID and selections before applying the edit
 7387                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7388
 7389                let snapshot = self.buffer.read(cx).snapshot(cx);
 7390                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7391
 7392                self.buffer.update(cx, |buffer, cx| {
 7393                    buffer.edit(edits.iter().cloned(), None, cx)
 7394                });
 7395
 7396                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7397                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7398                });
 7399
 7400                let selections = self.selections.disjoint_anchors();
 7401                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7402                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7403                    if has_new_transaction {
 7404                        self.selection_history
 7405                            .insert_transaction(transaction_id_now, selections);
 7406                    }
 7407                }
 7408
 7409                self.update_visible_edit_prediction(window, cx);
 7410                if self.active_edit_prediction.is_none() {
 7411                    self.refresh_edit_prediction(true, true, window, cx);
 7412                }
 7413
 7414                cx.notify();
 7415            }
 7416        }
 7417
 7418        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7419    }
 7420
 7421    pub fn accept_partial_edit_prediction(
 7422        &mut self,
 7423        _: &AcceptPartialEditPrediction,
 7424        window: &mut Window,
 7425        cx: &mut Context<Self>,
 7426    ) {
 7427        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7428            return;
 7429        };
 7430        if self.selections.count() != 1 {
 7431            return;
 7432        }
 7433
 7434        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7435
 7436        match &active_edit_prediction.completion {
 7437            EditPrediction::Move { target, .. } => {
 7438                let target = *target;
 7439                self.change_selections(
 7440                    SelectionEffects::scroll(Autoscroll::newest()),
 7441                    window,
 7442                    cx,
 7443                    |selections| {
 7444                        selections.select_anchor_ranges([target..target]);
 7445                    },
 7446                );
 7447            }
 7448            EditPrediction::Edit { edits, .. } => {
 7449                // Find an insertion that starts at the cursor position.
 7450                let snapshot = self.buffer.read(cx).snapshot(cx);
 7451                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7452                let insertion = edits.iter().find_map(|(range, text)| {
 7453                    let range = range.to_offset(&snapshot);
 7454                    if range.is_empty() && range.start == cursor_offset {
 7455                        Some(text)
 7456                    } else {
 7457                        None
 7458                    }
 7459                });
 7460
 7461                if let Some(text) = insertion {
 7462                    let mut partial_completion = text
 7463                        .chars()
 7464                        .by_ref()
 7465                        .take_while(|c| c.is_alphabetic())
 7466                        .collect::<String>();
 7467                    if partial_completion.is_empty() {
 7468                        partial_completion = text
 7469                            .chars()
 7470                            .by_ref()
 7471                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7472                            .collect::<String>();
 7473                    }
 7474
 7475                    cx.emit(EditorEvent::InputHandled {
 7476                        utf16_range_to_replace: None,
 7477                        text: partial_completion.clone().into(),
 7478                    });
 7479
 7480                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7481
 7482                    self.refresh_edit_prediction(true, true, window, cx);
 7483                    cx.notify();
 7484                } else {
 7485                    self.accept_edit_prediction(&Default::default(), window, cx);
 7486                }
 7487            }
 7488        }
 7489    }
 7490
 7491    fn discard_edit_prediction(
 7492        &mut self,
 7493        should_report_edit_prediction_event: bool,
 7494        cx: &mut Context<Self>,
 7495    ) -> bool {
 7496        if should_report_edit_prediction_event {
 7497            let completion_id = self
 7498                .active_edit_prediction
 7499                .as_ref()
 7500                .and_then(|active_completion| active_completion.completion_id.clone());
 7501
 7502            self.report_edit_prediction_event(completion_id, false, cx);
 7503        }
 7504
 7505        if let Some(provider) = self.edit_prediction_provider() {
 7506            provider.discard(cx);
 7507        }
 7508
 7509        self.take_active_edit_prediction(cx)
 7510    }
 7511
 7512    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7513        let Some(provider) = self.edit_prediction_provider() else {
 7514            return;
 7515        };
 7516
 7517        let Some((_, buffer, _)) = self
 7518            .buffer
 7519            .read(cx)
 7520            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7521        else {
 7522            return;
 7523        };
 7524
 7525        let extension = buffer
 7526            .read(cx)
 7527            .file()
 7528            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7529
 7530        let event_type = match accepted {
 7531            true => "Edit Prediction Accepted",
 7532            false => "Edit Prediction Discarded",
 7533        };
 7534        telemetry::event!(
 7535            event_type,
 7536            provider = provider.name(),
 7537            prediction_id = id,
 7538            suggestion_accepted = accepted,
 7539            file_extension = extension,
 7540        );
 7541    }
 7542
 7543    pub fn has_active_edit_prediction(&self) -> bool {
 7544        self.active_edit_prediction.is_some()
 7545    }
 7546
 7547    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7548        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7549            return false;
 7550        };
 7551
 7552        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7553        self.clear_highlights::<EditPredictionHighlight>(cx);
 7554        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7555        true
 7556    }
 7557
 7558    /// Returns true when we're displaying the edit prediction popover below the cursor
 7559    /// like we are not previewing and the LSP autocomplete menu is visible
 7560    /// or we are in `when_holding_modifier` mode.
 7561    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7562        if self.edit_prediction_preview_is_active()
 7563            || !self.show_edit_predictions_in_menu()
 7564            || !self.edit_predictions_enabled()
 7565        {
 7566            return false;
 7567        }
 7568
 7569        if self.has_visible_completions_menu() {
 7570            return true;
 7571        }
 7572
 7573        has_completion && self.edit_prediction_requires_modifier()
 7574    }
 7575
 7576    fn handle_modifiers_changed(
 7577        &mut self,
 7578        modifiers: Modifiers,
 7579        position_map: &PositionMap,
 7580        window: &mut Window,
 7581        cx: &mut Context<Self>,
 7582    ) {
 7583        if self.show_edit_predictions_in_menu() {
 7584            self.update_edit_prediction_preview(&modifiers, window, cx);
 7585        }
 7586
 7587        self.update_selection_mode(&modifiers, position_map, window, cx);
 7588
 7589        let mouse_position = window.mouse_position();
 7590        if !position_map.text_hitbox.is_hovered(window) {
 7591            return;
 7592        }
 7593
 7594        self.update_hovered_link(
 7595            position_map.point_for_position(mouse_position),
 7596            &position_map.snapshot,
 7597            modifiers,
 7598            window,
 7599            cx,
 7600        )
 7601    }
 7602
 7603    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7604        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7605        if invert {
 7606            match multi_cursor_setting {
 7607                MultiCursorModifier::Alt => modifiers.alt,
 7608                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7609            }
 7610        } else {
 7611            match multi_cursor_setting {
 7612                MultiCursorModifier::Alt => modifiers.secondary(),
 7613                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7614            }
 7615        }
 7616    }
 7617
 7618    fn columnar_selection_mode(
 7619        modifiers: &Modifiers,
 7620        cx: &mut Context<Self>,
 7621    ) -> Option<ColumnarMode> {
 7622        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7623            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7624                Some(ColumnarMode::FromMouse)
 7625            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7626                Some(ColumnarMode::FromSelection)
 7627            } else {
 7628                None
 7629            }
 7630        } else {
 7631            None
 7632        }
 7633    }
 7634
 7635    fn update_selection_mode(
 7636        &mut self,
 7637        modifiers: &Modifiers,
 7638        position_map: &PositionMap,
 7639        window: &mut Window,
 7640        cx: &mut Context<Self>,
 7641    ) {
 7642        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7643            return;
 7644        };
 7645        if self.selections.pending.is_none() {
 7646            return;
 7647        }
 7648
 7649        let mouse_position = window.mouse_position();
 7650        let point_for_position = position_map.point_for_position(mouse_position);
 7651        let position = point_for_position.previous_valid;
 7652
 7653        self.select(
 7654            SelectPhase::BeginColumnar {
 7655                position,
 7656                reset: false,
 7657                mode,
 7658                goal_column: point_for_position.exact_unclipped.column(),
 7659            },
 7660            window,
 7661            cx,
 7662        );
 7663    }
 7664
 7665    fn update_edit_prediction_preview(
 7666        &mut self,
 7667        modifiers: &Modifiers,
 7668        window: &mut Window,
 7669        cx: &mut Context<Self>,
 7670    ) {
 7671        let mut modifiers_held = false;
 7672        if let Some(accept_keystroke) = self
 7673            .accept_edit_prediction_keybind(false, window, cx)
 7674            .keystroke()
 7675        {
 7676            modifiers_held = modifiers_held
 7677                || (&accept_keystroke.modifiers == modifiers
 7678                    && accept_keystroke.modifiers.modified());
 7679        };
 7680        if let Some(accept_partial_keystroke) = self
 7681            .accept_edit_prediction_keybind(true, window, cx)
 7682            .keystroke()
 7683        {
 7684            modifiers_held = modifiers_held
 7685                || (&accept_partial_keystroke.modifiers == modifiers
 7686                    && accept_partial_keystroke.modifiers.modified());
 7687        }
 7688
 7689        if modifiers_held {
 7690            if matches!(
 7691                self.edit_prediction_preview,
 7692                EditPredictionPreview::Inactive { .. }
 7693            ) {
 7694                self.edit_prediction_preview = EditPredictionPreview::Active {
 7695                    previous_scroll_position: None,
 7696                    since: Instant::now(),
 7697                };
 7698
 7699                self.update_visible_edit_prediction(window, cx);
 7700                cx.notify();
 7701            }
 7702        } else if let EditPredictionPreview::Active {
 7703            previous_scroll_position,
 7704            since,
 7705        } = self.edit_prediction_preview
 7706        {
 7707            if let (Some(previous_scroll_position), Some(position_map)) =
 7708                (previous_scroll_position, self.last_position_map.as_ref())
 7709            {
 7710                self.set_scroll_position(
 7711                    previous_scroll_position
 7712                        .scroll_position(&position_map.snapshot.display_snapshot),
 7713                    window,
 7714                    cx,
 7715                );
 7716            }
 7717
 7718            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7719                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7720            };
 7721            self.clear_row_highlights::<EditPredictionPreview>();
 7722            self.update_visible_edit_prediction(window, cx);
 7723            cx.notify();
 7724        }
 7725    }
 7726
 7727    fn update_visible_edit_prediction(
 7728        &mut self,
 7729        _window: &mut Window,
 7730        cx: &mut Context<Self>,
 7731    ) -> Option<()> {
 7732        if DisableAiSettings::get_global(cx).disable_ai {
 7733            return None;
 7734        }
 7735
 7736        let selection = self.selections.newest_anchor();
 7737        let cursor = selection.head();
 7738        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7739        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7740        let excerpt_id = cursor.excerpt_id;
 7741
 7742        let show_in_menu = self.show_edit_predictions_in_menu();
 7743        let completions_menu_has_precedence = !show_in_menu
 7744            && (self.context_menu.borrow().is_some()
 7745                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7746
 7747        if completions_menu_has_precedence
 7748            || !offset_selection.is_empty()
 7749            || self
 7750                .active_edit_prediction
 7751                .as_ref()
 7752                .is_some_and(|completion| {
 7753                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7754                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7755                    !invalidation_range.contains(&offset_selection.head())
 7756                })
 7757        {
 7758            self.discard_edit_prediction(false, cx);
 7759            return None;
 7760        }
 7761
 7762        self.take_active_edit_prediction(cx);
 7763        let Some(provider) = self.edit_prediction_provider() else {
 7764            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7765            return None;
 7766        };
 7767
 7768        let (buffer, cursor_buffer_position) =
 7769            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7770
 7771        self.edit_prediction_settings =
 7772            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7773
 7774        match self.edit_prediction_settings {
 7775            EditPredictionSettings::Disabled => {
 7776                self.discard_edit_prediction(false, cx);
 7777                return None;
 7778            }
 7779            _ => {}
 7780        };
 7781
 7782        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7783
 7784        if self.edit_prediction_indent_conflict {
 7785            let cursor_point = cursor.to_point(&multibuffer);
 7786
 7787            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7788
 7789            if let Some((_, indent)) = indents.iter().next()
 7790                && indent.len == cursor_point.column
 7791            {
 7792                self.edit_prediction_indent_conflict = false;
 7793            }
 7794        }
 7795
 7796        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7797        let edits = edit_prediction
 7798            .edits
 7799            .into_iter()
 7800            .flat_map(|(range, new_text)| {
 7801                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7802                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7803                Some((start..end, new_text))
 7804            })
 7805            .collect::<Vec<_>>();
 7806        if edits.is_empty() {
 7807            return None;
 7808        }
 7809
 7810        let first_edit_start = edits.first().unwrap().0.start;
 7811        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7812        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7813
 7814        let last_edit_end = edits.last().unwrap().0.end;
 7815        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7816        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7817
 7818        let cursor_row = cursor.to_point(&multibuffer).row;
 7819
 7820        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7821
 7822        let mut inlay_ids = Vec::new();
 7823        let invalidation_row_range;
 7824        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7825            Some(cursor_row..edit_end_row)
 7826        } else if cursor_row > edit_end_row {
 7827            Some(edit_start_row..cursor_row)
 7828        } else {
 7829            None
 7830        };
 7831        let supports_jump = self
 7832            .edit_prediction_provider
 7833            .as_ref()
 7834            .map(|provider| provider.provider.supports_jump_to_edit())
 7835            .unwrap_or(true);
 7836
 7837        let is_move = supports_jump
 7838            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7839        let completion = if is_move {
 7840            invalidation_row_range =
 7841                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7842            let target = first_edit_start;
 7843            EditPrediction::Move { target, snapshot }
 7844        } else {
 7845            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7846                && !self.edit_predictions_hidden_for_vim_mode;
 7847
 7848            if show_completions_in_buffer {
 7849                if edits
 7850                    .iter()
 7851                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7852                {
 7853                    let mut inlays = Vec::new();
 7854                    for (range, new_text) in &edits {
 7855                        let inlay = Inlay::edit_prediction(
 7856                            post_inc(&mut self.next_inlay_id),
 7857                            range.start,
 7858                            new_text.as_str(),
 7859                        );
 7860                        inlay_ids.push(inlay.id);
 7861                        inlays.push(inlay);
 7862                    }
 7863
 7864                    self.splice_inlays(&[], inlays, cx);
 7865                } else {
 7866                    let background_color = cx.theme().status().deleted_background;
 7867                    self.highlight_text::<EditPredictionHighlight>(
 7868                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7869                        HighlightStyle {
 7870                            background_color: Some(background_color),
 7871                            ..Default::default()
 7872                        },
 7873                        cx,
 7874                    );
 7875                }
 7876            }
 7877
 7878            invalidation_row_range = edit_start_row..edit_end_row;
 7879
 7880            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7881                if provider.show_tab_accept_marker() {
 7882                    EditDisplayMode::TabAccept
 7883                } else {
 7884                    EditDisplayMode::Inline
 7885                }
 7886            } else {
 7887                EditDisplayMode::DiffPopover
 7888            };
 7889
 7890            EditPrediction::Edit {
 7891                edits,
 7892                edit_preview: edit_prediction.edit_preview,
 7893                display_mode,
 7894                snapshot,
 7895            }
 7896        };
 7897
 7898        let invalidation_range = multibuffer
 7899            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7900            ..multibuffer.anchor_after(Point::new(
 7901                invalidation_row_range.end,
 7902                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7903            ));
 7904
 7905        self.stale_edit_prediction_in_menu = None;
 7906        self.active_edit_prediction = Some(EditPredictionState {
 7907            inlay_ids,
 7908            completion,
 7909            completion_id: edit_prediction.id,
 7910            invalidation_range,
 7911        });
 7912
 7913        cx.notify();
 7914
 7915        Some(())
 7916    }
 7917
 7918    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7919        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7920    }
 7921
 7922    fn clear_tasks(&mut self) {
 7923        self.tasks.clear()
 7924    }
 7925
 7926    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7927        if self.tasks.insert(key, value).is_some() {
 7928            // This case should hopefully be rare, but just in case...
 7929            log::error!(
 7930                "multiple different run targets found on a single line, only the last target will be rendered"
 7931            )
 7932        }
 7933    }
 7934
 7935    /// Get all display points of breakpoints that will be rendered within editor
 7936    ///
 7937    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7938    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7939    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7940    fn active_breakpoints(
 7941        &self,
 7942        range: Range<DisplayRow>,
 7943        window: &mut Window,
 7944        cx: &mut Context<Self>,
 7945    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7946        let mut breakpoint_display_points = HashMap::default();
 7947
 7948        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7949            return breakpoint_display_points;
 7950        };
 7951
 7952        let snapshot = self.snapshot(window, cx);
 7953
 7954        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7955        let Some(project) = self.project() else {
 7956            return breakpoint_display_points;
 7957        };
 7958
 7959        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7960            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7961
 7962        for (buffer_snapshot, range, excerpt_id) in
 7963            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7964        {
 7965            let Some(buffer) = project
 7966                .read(cx)
 7967                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7968            else {
 7969                continue;
 7970            };
 7971            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7972                &buffer,
 7973                Some(
 7974                    buffer_snapshot.anchor_before(range.start)
 7975                        ..buffer_snapshot.anchor_after(range.end),
 7976                ),
 7977                buffer_snapshot,
 7978                cx,
 7979            );
 7980            for (breakpoint, state) in breakpoints {
 7981                let multi_buffer_anchor =
 7982                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7983                let position = multi_buffer_anchor
 7984                    .to_point(multi_buffer_snapshot)
 7985                    .to_display_point(&snapshot);
 7986
 7987                breakpoint_display_points.insert(
 7988                    position.row(),
 7989                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7990                );
 7991            }
 7992        }
 7993
 7994        breakpoint_display_points
 7995    }
 7996
 7997    fn breakpoint_context_menu(
 7998        &self,
 7999        anchor: Anchor,
 8000        window: &mut Window,
 8001        cx: &mut Context<Self>,
 8002    ) -> Entity<ui::ContextMenu> {
 8003        let weak_editor = cx.weak_entity();
 8004        let focus_handle = self.focus_handle(cx);
 8005
 8006        let row = self
 8007            .buffer
 8008            .read(cx)
 8009            .snapshot(cx)
 8010            .summary_for_anchor::<Point>(&anchor)
 8011            .row;
 8012
 8013        let breakpoint = self
 8014            .breakpoint_at_row(row, window, cx)
 8015            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8016
 8017        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8018            "Edit Log Breakpoint"
 8019        } else {
 8020            "Set Log Breakpoint"
 8021        };
 8022
 8023        let condition_breakpoint_msg = if breakpoint
 8024            .as_ref()
 8025            .is_some_and(|bp| bp.1.condition.is_some())
 8026        {
 8027            "Edit Condition Breakpoint"
 8028        } else {
 8029            "Set Condition Breakpoint"
 8030        };
 8031
 8032        let hit_condition_breakpoint_msg = if breakpoint
 8033            .as_ref()
 8034            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8035        {
 8036            "Edit Hit Condition Breakpoint"
 8037        } else {
 8038            "Set Hit Condition Breakpoint"
 8039        };
 8040
 8041        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8042            "Unset Breakpoint"
 8043        } else {
 8044            "Set Breakpoint"
 8045        };
 8046
 8047        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8048
 8049        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8050            BreakpointState::Enabled => Some("Disable"),
 8051            BreakpointState::Disabled => Some("Enable"),
 8052        });
 8053
 8054        let (anchor, breakpoint) =
 8055            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8056
 8057        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8058            menu.on_blur_subscription(Subscription::new(|| {}))
 8059                .context(focus_handle)
 8060                .when(run_to_cursor, |this| {
 8061                    let weak_editor = weak_editor.clone();
 8062                    this.entry("Run to cursor", None, move |window, cx| {
 8063                        weak_editor
 8064                            .update(cx, |editor, cx| {
 8065                                editor.change_selections(
 8066                                    SelectionEffects::no_scroll(),
 8067                                    window,
 8068                                    cx,
 8069                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8070                                );
 8071                            })
 8072                            .ok();
 8073
 8074                        window.dispatch_action(Box::new(RunToCursor), cx);
 8075                    })
 8076                    .separator()
 8077                })
 8078                .when_some(toggle_state_msg, |this, msg| {
 8079                    this.entry(msg, None, {
 8080                        let weak_editor = weak_editor.clone();
 8081                        let breakpoint = breakpoint.clone();
 8082                        move |_window, cx| {
 8083                            weak_editor
 8084                                .update(cx, |this, cx| {
 8085                                    this.edit_breakpoint_at_anchor(
 8086                                        anchor,
 8087                                        breakpoint.as_ref().clone(),
 8088                                        BreakpointEditAction::InvertState,
 8089                                        cx,
 8090                                    );
 8091                                })
 8092                                .log_err();
 8093                        }
 8094                    })
 8095                })
 8096                .entry(set_breakpoint_msg, None, {
 8097                    let weak_editor = weak_editor.clone();
 8098                    let breakpoint = breakpoint.clone();
 8099                    move |_window, cx| {
 8100                        weak_editor
 8101                            .update(cx, |this, cx| {
 8102                                this.edit_breakpoint_at_anchor(
 8103                                    anchor,
 8104                                    breakpoint.as_ref().clone(),
 8105                                    BreakpointEditAction::Toggle,
 8106                                    cx,
 8107                                );
 8108                            })
 8109                            .log_err();
 8110                    }
 8111                })
 8112                .entry(log_breakpoint_msg, None, {
 8113                    let breakpoint = breakpoint.clone();
 8114                    let weak_editor = weak_editor.clone();
 8115                    move |window, cx| {
 8116                        weak_editor
 8117                            .update(cx, |this, cx| {
 8118                                this.add_edit_breakpoint_block(
 8119                                    anchor,
 8120                                    breakpoint.as_ref(),
 8121                                    BreakpointPromptEditAction::Log,
 8122                                    window,
 8123                                    cx,
 8124                                );
 8125                            })
 8126                            .log_err();
 8127                    }
 8128                })
 8129                .entry(condition_breakpoint_msg, None, {
 8130                    let breakpoint = breakpoint.clone();
 8131                    let weak_editor = weak_editor.clone();
 8132                    move |window, cx| {
 8133                        weak_editor
 8134                            .update(cx, |this, cx| {
 8135                                this.add_edit_breakpoint_block(
 8136                                    anchor,
 8137                                    breakpoint.as_ref(),
 8138                                    BreakpointPromptEditAction::Condition,
 8139                                    window,
 8140                                    cx,
 8141                                );
 8142                            })
 8143                            .log_err();
 8144                    }
 8145                })
 8146                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8147                    weak_editor
 8148                        .update(cx, |this, cx| {
 8149                            this.add_edit_breakpoint_block(
 8150                                anchor,
 8151                                breakpoint.as_ref(),
 8152                                BreakpointPromptEditAction::HitCondition,
 8153                                window,
 8154                                cx,
 8155                            );
 8156                        })
 8157                        .log_err();
 8158                })
 8159        })
 8160    }
 8161
 8162    fn render_breakpoint(
 8163        &self,
 8164        position: Anchor,
 8165        row: DisplayRow,
 8166        breakpoint: &Breakpoint,
 8167        state: Option<BreakpointSessionState>,
 8168        cx: &mut Context<Self>,
 8169    ) -> IconButton {
 8170        let is_rejected = state.is_some_and(|s| !s.verified);
 8171        // Is it a breakpoint that shows up when hovering over gutter?
 8172        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8173            (false, false),
 8174            |PhantomBreakpointIndicator {
 8175                 is_active,
 8176                 display_row,
 8177                 collides_with_existing_breakpoint,
 8178             }| {
 8179                (
 8180                    is_active && display_row == row,
 8181                    collides_with_existing_breakpoint,
 8182                )
 8183            },
 8184        );
 8185
 8186        let (color, icon) = {
 8187            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8188                (false, false) => ui::IconName::DebugBreakpoint,
 8189                (true, false) => ui::IconName::DebugLogBreakpoint,
 8190                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8191                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8192            };
 8193
 8194            let color = if is_phantom {
 8195                Color::Hint
 8196            } else if is_rejected {
 8197                Color::Disabled
 8198            } else {
 8199                Color::Debugger
 8200            };
 8201
 8202            (color, icon)
 8203        };
 8204
 8205        let breakpoint = Arc::from(breakpoint.clone());
 8206
 8207        let alt_as_text = gpui::Keystroke {
 8208            modifiers: Modifiers::secondary_key(),
 8209            ..Default::default()
 8210        };
 8211        let primary_action_text = if breakpoint.is_disabled() {
 8212            "Enable breakpoint"
 8213        } else if is_phantom && !collides_with_existing {
 8214            "Set breakpoint"
 8215        } else {
 8216            "Unset breakpoint"
 8217        };
 8218        let focus_handle = self.focus_handle.clone();
 8219
 8220        let meta = if is_rejected {
 8221            SharedString::from("No executable code is associated with this line.")
 8222        } else if collides_with_existing && !breakpoint.is_disabled() {
 8223            SharedString::from(format!(
 8224                "{alt_as_text}-click to disable,\nright-click for more options."
 8225            ))
 8226        } else {
 8227            SharedString::from("Right-click for more options.")
 8228        };
 8229        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8230            .icon_size(IconSize::XSmall)
 8231            .size(ui::ButtonSize::None)
 8232            .when(is_rejected, |this| {
 8233                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8234            })
 8235            .icon_color(color)
 8236            .style(ButtonStyle::Transparent)
 8237            .on_click(cx.listener({
 8238                let breakpoint = breakpoint.clone();
 8239
 8240                move |editor, event: &ClickEvent, window, cx| {
 8241                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8242                        BreakpointEditAction::InvertState
 8243                    } else {
 8244                        BreakpointEditAction::Toggle
 8245                    };
 8246
 8247                    window.focus(&editor.focus_handle(cx));
 8248                    editor.edit_breakpoint_at_anchor(
 8249                        position,
 8250                        breakpoint.as_ref().clone(),
 8251                        edit_action,
 8252                        cx,
 8253                    );
 8254                }
 8255            }))
 8256            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8257                editor.set_breakpoint_context_menu(
 8258                    row,
 8259                    Some(position),
 8260                    event.position(),
 8261                    window,
 8262                    cx,
 8263                );
 8264            }))
 8265            .tooltip(move |window, cx| {
 8266                Tooltip::with_meta_in(
 8267                    primary_action_text,
 8268                    Some(&ToggleBreakpoint),
 8269                    meta.clone(),
 8270                    &focus_handle,
 8271                    window,
 8272                    cx,
 8273                )
 8274            })
 8275    }
 8276
 8277    fn build_tasks_context(
 8278        project: &Entity<Project>,
 8279        buffer: &Entity<Buffer>,
 8280        buffer_row: u32,
 8281        tasks: &Arc<RunnableTasks>,
 8282        cx: &mut Context<Self>,
 8283    ) -> Task<Option<task::TaskContext>> {
 8284        let position = Point::new(buffer_row, tasks.column);
 8285        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8286        let location = Location {
 8287            buffer: buffer.clone(),
 8288            range: range_start..range_start,
 8289        };
 8290        // Fill in the environmental variables from the tree-sitter captures
 8291        let mut captured_task_variables = TaskVariables::default();
 8292        for (capture_name, value) in tasks.extra_variables.clone() {
 8293            captured_task_variables.insert(
 8294                task::VariableName::Custom(capture_name.into()),
 8295                value.clone(),
 8296            );
 8297        }
 8298        project.update(cx, |project, cx| {
 8299            project.task_store().update(cx, |task_store, cx| {
 8300                task_store.task_context_for_location(captured_task_variables, location, cx)
 8301            })
 8302        })
 8303    }
 8304
 8305    pub fn spawn_nearest_task(
 8306        &mut self,
 8307        action: &SpawnNearestTask,
 8308        window: &mut Window,
 8309        cx: &mut Context<Self>,
 8310    ) {
 8311        let Some((workspace, _)) = self.workspace.clone() else {
 8312            return;
 8313        };
 8314        let Some(project) = self.project.clone() else {
 8315            return;
 8316        };
 8317
 8318        // Try to find a closest, enclosing node using tree-sitter that has a task
 8319        let Some((buffer, buffer_row, tasks)) = self
 8320            .find_enclosing_node_task(cx)
 8321            // Or find the task that's closest in row-distance.
 8322            .or_else(|| self.find_closest_task(cx))
 8323        else {
 8324            return;
 8325        };
 8326
 8327        let reveal_strategy = action.reveal;
 8328        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8329        cx.spawn_in(window, async move |_, cx| {
 8330            let context = task_context.await?;
 8331            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8332
 8333            let resolved = &mut resolved_task.resolved;
 8334            resolved.reveal = reveal_strategy;
 8335
 8336            workspace
 8337                .update_in(cx, |workspace, window, cx| {
 8338                    workspace.schedule_resolved_task(
 8339                        task_source_kind,
 8340                        resolved_task,
 8341                        false,
 8342                        window,
 8343                        cx,
 8344                    );
 8345                })
 8346                .ok()
 8347        })
 8348        .detach();
 8349    }
 8350
 8351    fn find_closest_task(
 8352        &mut self,
 8353        cx: &mut Context<Self>,
 8354    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8355        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8356
 8357        let ((buffer_id, row), tasks) = self
 8358            .tasks
 8359            .iter()
 8360            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8361
 8362        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8363        let tasks = Arc::new(tasks.to_owned());
 8364        Some((buffer, *row, tasks))
 8365    }
 8366
 8367    fn find_enclosing_node_task(
 8368        &mut self,
 8369        cx: &mut Context<Self>,
 8370    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8371        let snapshot = self.buffer.read(cx).snapshot(cx);
 8372        let offset = self.selections.newest::<usize>(cx).head();
 8373        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8374        let buffer_id = excerpt.buffer().remote_id();
 8375
 8376        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8377        let mut cursor = layer.node().walk();
 8378
 8379        while cursor.goto_first_child_for_byte(offset).is_some() {
 8380            if cursor.node().end_byte() == offset {
 8381                cursor.goto_next_sibling();
 8382            }
 8383        }
 8384
 8385        // Ascend to the smallest ancestor that contains the range and has a task.
 8386        loop {
 8387            let node = cursor.node();
 8388            let node_range = node.byte_range();
 8389            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8390
 8391            // Check if this node contains our offset
 8392            if node_range.start <= offset && node_range.end >= offset {
 8393                // If it contains offset, check for task
 8394                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8395                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8396                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8397                }
 8398            }
 8399
 8400            if !cursor.goto_parent() {
 8401                break;
 8402            }
 8403        }
 8404        None
 8405    }
 8406
 8407    fn render_run_indicator(
 8408        &self,
 8409        _style: &EditorStyle,
 8410        is_active: bool,
 8411        row: DisplayRow,
 8412        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8413        cx: &mut Context<Self>,
 8414    ) -> IconButton {
 8415        let color = Color::Muted;
 8416        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8417
 8418        IconButton::new(
 8419            ("run_indicator", row.0 as usize),
 8420            ui::IconName::PlayOutlined,
 8421        )
 8422        .shape(ui::IconButtonShape::Square)
 8423        .icon_size(IconSize::XSmall)
 8424        .icon_color(color)
 8425        .toggle_state(is_active)
 8426        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8427            let quick_launch = match e {
 8428                ClickEvent::Keyboard(_) => true,
 8429                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8430            };
 8431
 8432            window.focus(&editor.focus_handle(cx));
 8433            editor.toggle_code_actions(
 8434                &ToggleCodeActions {
 8435                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8436                    quick_launch,
 8437                },
 8438                window,
 8439                cx,
 8440            );
 8441        }))
 8442        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8443            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8444        }))
 8445    }
 8446
 8447    pub fn context_menu_visible(&self) -> bool {
 8448        !self.edit_prediction_preview_is_active()
 8449            && self
 8450                .context_menu
 8451                .borrow()
 8452                .as_ref()
 8453                .is_some_and(|menu| menu.visible())
 8454    }
 8455
 8456    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8457        self.context_menu
 8458            .borrow()
 8459            .as_ref()
 8460            .map(|menu| menu.origin())
 8461    }
 8462
 8463    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8464        self.context_menu_options = Some(options);
 8465    }
 8466
 8467    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8468    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8469
 8470    fn render_edit_prediction_popover(
 8471        &mut self,
 8472        text_bounds: &Bounds<Pixels>,
 8473        content_origin: gpui::Point<Pixels>,
 8474        right_margin: Pixels,
 8475        editor_snapshot: &EditorSnapshot,
 8476        visible_row_range: Range<DisplayRow>,
 8477        scroll_top: f32,
 8478        scroll_bottom: f32,
 8479        line_layouts: &[LineWithInvisibles],
 8480        line_height: Pixels,
 8481        scroll_pixel_position: gpui::Point<Pixels>,
 8482        newest_selection_head: Option<DisplayPoint>,
 8483        editor_width: Pixels,
 8484        style: &EditorStyle,
 8485        window: &mut Window,
 8486        cx: &mut App,
 8487    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8488        if self.mode().is_minimap() {
 8489            return None;
 8490        }
 8491        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8492
 8493        if self.edit_prediction_visible_in_cursor_popover(true) {
 8494            return None;
 8495        }
 8496
 8497        match &active_edit_prediction.completion {
 8498            EditPrediction::Move { target, .. } => {
 8499                let target_display_point = target.to_display_point(editor_snapshot);
 8500
 8501                if self.edit_prediction_requires_modifier() {
 8502                    if !self.edit_prediction_preview_is_active() {
 8503                        return None;
 8504                    }
 8505
 8506                    self.render_edit_prediction_modifier_jump_popover(
 8507                        text_bounds,
 8508                        content_origin,
 8509                        visible_row_range,
 8510                        line_layouts,
 8511                        line_height,
 8512                        scroll_pixel_position,
 8513                        newest_selection_head,
 8514                        target_display_point,
 8515                        window,
 8516                        cx,
 8517                    )
 8518                } else {
 8519                    self.render_edit_prediction_eager_jump_popover(
 8520                        text_bounds,
 8521                        content_origin,
 8522                        editor_snapshot,
 8523                        visible_row_range,
 8524                        scroll_top,
 8525                        scroll_bottom,
 8526                        line_height,
 8527                        scroll_pixel_position,
 8528                        target_display_point,
 8529                        editor_width,
 8530                        window,
 8531                        cx,
 8532                    )
 8533                }
 8534            }
 8535            EditPrediction::Edit {
 8536                display_mode: EditDisplayMode::Inline,
 8537                ..
 8538            } => None,
 8539            EditPrediction::Edit {
 8540                display_mode: EditDisplayMode::TabAccept,
 8541                edits,
 8542                ..
 8543            } => {
 8544                let range = &edits.first()?.0;
 8545                let target_display_point = range.end.to_display_point(editor_snapshot);
 8546
 8547                self.render_edit_prediction_end_of_line_popover(
 8548                    "Accept",
 8549                    editor_snapshot,
 8550                    visible_row_range,
 8551                    target_display_point,
 8552                    line_height,
 8553                    scroll_pixel_position,
 8554                    content_origin,
 8555                    editor_width,
 8556                    window,
 8557                    cx,
 8558                )
 8559            }
 8560            EditPrediction::Edit {
 8561                edits,
 8562                edit_preview,
 8563                display_mode: EditDisplayMode::DiffPopover,
 8564                snapshot,
 8565            } => self.render_edit_prediction_diff_popover(
 8566                text_bounds,
 8567                content_origin,
 8568                right_margin,
 8569                editor_snapshot,
 8570                visible_row_range,
 8571                line_layouts,
 8572                line_height,
 8573                scroll_pixel_position,
 8574                newest_selection_head,
 8575                editor_width,
 8576                style,
 8577                edits,
 8578                edit_preview,
 8579                snapshot,
 8580                window,
 8581                cx,
 8582            ),
 8583        }
 8584    }
 8585
 8586    fn render_edit_prediction_modifier_jump_popover(
 8587        &mut self,
 8588        text_bounds: &Bounds<Pixels>,
 8589        content_origin: gpui::Point<Pixels>,
 8590        visible_row_range: Range<DisplayRow>,
 8591        line_layouts: &[LineWithInvisibles],
 8592        line_height: Pixels,
 8593        scroll_pixel_position: gpui::Point<Pixels>,
 8594        newest_selection_head: Option<DisplayPoint>,
 8595        target_display_point: DisplayPoint,
 8596        window: &mut Window,
 8597        cx: &mut App,
 8598    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8599        let scrolled_content_origin =
 8600            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8601
 8602        const SCROLL_PADDING_Y: Pixels = px(12.);
 8603
 8604        if target_display_point.row() < visible_row_range.start {
 8605            return self.render_edit_prediction_scroll_popover(
 8606                |_| SCROLL_PADDING_Y,
 8607                IconName::ArrowUp,
 8608                visible_row_range,
 8609                line_layouts,
 8610                newest_selection_head,
 8611                scrolled_content_origin,
 8612                window,
 8613                cx,
 8614            );
 8615        } else if target_display_point.row() >= visible_row_range.end {
 8616            return self.render_edit_prediction_scroll_popover(
 8617                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8618                IconName::ArrowDown,
 8619                visible_row_range,
 8620                line_layouts,
 8621                newest_selection_head,
 8622                scrolled_content_origin,
 8623                window,
 8624                cx,
 8625            );
 8626        }
 8627
 8628        const POLE_WIDTH: Pixels = px(2.);
 8629
 8630        let line_layout =
 8631            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8632        let target_column = target_display_point.column() as usize;
 8633
 8634        let target_x = line_layout.x_for_index(target_column);
 8635        let target_y =
 8636            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8637
 8638        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8639
 8640        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8641        border_color.l += 0.001;
 8642
 8643        let mut element = v_flex()
 8644            .items_end()
 8645            .when(flag_on_right, |el| el.items_start())
 8646            .child(if flag_on_right {
 8647                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8648                    .rounded_bl(px(0.))
 8649                    .rounded_tl(px(0.))
 8650                    .border_l_2()
 8651                    .border_color(border_color)
 8652            } else {
 8653                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8654                    .rounded_br(px(0.))
 8655                    .rounded_tr(px(0.))
 8656                    .border_r_2()
 8657                    .border_color(border_color)
 8658            })
 8659            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8660            .into_any();
 8661
 8662        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8663
 8664        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8665            - point(
 8666                if flag_on_right {
 8667                    POLE_WIDTH
 8668                } else {
 8669                    size.width - POLE_WIDTH
 8670                },
 8671                size.height - line_height,
 8672            );
 8673
 8674        origin.x = origin.x.max(content_origin.x);
 8675
 8676        element.prepaint_at(origin, window, cx);
 8677
 8678        Some((element, origin))
 8679    }
 8680
 8681    fn render_edit_prediction_scroll_popover(
 8682        &mut self,
 8683        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8684        scroll_icon: IconName,
 8685        visible_row_range: Range<DisplayRow>,
 8686        line_layouts: &[LineWithInvisibles],
 8687        newest_selection_head: Option<DisplayPoint>,
 8688        scrolled_content_origin: gpui::Point<Pixels>,
 8689        window: &mut Window,
 8690        cx: &mut App,
 8691    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8692        let mut element = self
 8693            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8694            .into_any();
 8695
 8696        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8697
 8698        let cursor = newest_selection_head?;
 8699        let cursor_row_layout =
 8700            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8701        let cursor_column = cursor.column() as usize;
 8702
 8703        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8704
 8705        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8706
 8707        element.prepaint_at(origin, window, cx);
 8708        Some((element, origin))
 8709    }
 8710
 8711    fn render_edit_prediction_eager_jump_popover(
 8712        &mut self,
 8713        text_bounds: &Bounds<Pixels>,
 8714        content_origin: gpui::Point<Pixels>,
 8715        editor_snapshot: &EditorSnapshot,
 8716        visible_row_range: Range<DisplayRow>,
 8717        scroll_top: f32,
 8718        scroll_bottom: f32,
 8719        line_height: Pixels,
 8720        scroll_pixel_position: gpui::Point<Pixels>,
 8721        target_display_point: DisplayPoint,
 8722        editor_width: Pixels,
 8723        window: &mut Window,
 8724        cx: &mut App,
 8725    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8726        if target_display_point.row().as_f32() < scroll_top {
 8727            let mut element = self
 8728                .render_edit_prediction_line_popover(
 8729                    "Jump to Edit",
 8730                    Some(IconName::ArrowUp),
 8731                    window,
 8732                    cx,
 8733                )?
 8734                .into_any();
 8735
 8736            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8737            let offset = point(
 8738                (text_bounds.size.width - size.width) / 2.,
 8739                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8740            );
 8741
 8742            let origin = text_bounds.origin + offset;
 8743            element.prepaint_at(origin, window, cx);
 8744            Some((element, origin))
 8745        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8746            let mut element = self
 8747                .render_edit_prediction_line_popover(
 8748                    "Jump to Edit",
 8749                    Some(IconName::ArrowDown),
 8750                    window,
 8751                    cx,
 8752                )?
 8753                .into_any();
 8754
 8755            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8756            let offset = point(
 8757                (text_bounds.size.width - size.width) / 2.,
 8758                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8759            );
 8760
 8761            let origin = text_bounds.origin + offset;
 8762            element.prepaint_at(origin, window, cx);
 8763            Some((element, origin))
 8764        } else {
 8765            self.render_edit_prediction_end_of_line_popover(
 8766                "Jump to Edit",
 8767                editor_snapshot,
 8768                visible_row_range,
 8769                target_display_point,
 8770                line_height,
 8771                scroll_pixel_position,
 8772                content_origin,
 8773                editor_width,
 8774                window,
 8775                cx,
 8776            )
 8777        }
 8778    }
 8779
 8780    fn render_edit_prediction_end_of_line_popover(
 8781        self: &mut Editor,
 8782        label: &'static str,
 8783        editor_snapshot: &EditorSnapshot,
 8784        visible_row_range: Range<DisplayRow>,
 8785        target_display_point: DisplayPoint,
 8786        line_height: Pixels,
 8787        scroll_pixel_position: gpui::Point<Pixels>,
 8788        content_origin: gpui::Point<Pixels>,
 8789        editor_width: Pixels,
 8790        window: &mut Window,
 8791        cx: &mut App,
 8792    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8793        let target_line_end = DisplayPoint::new(
 8794            target_display_point.row(),
 8795            editor_snapshot.line_len(target_display_point.row()),
 8796        );
 8797
 8798        let mut element = self
 8799            .render_edit_prediction_line_popover(label, None, window, cx)?
 8800            .into_any();
 8801
 8802        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8803
 8804        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8805
 8806        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8807        let mut origin = start_point
 8808            + line_origin
 8809            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8810        origin.x = origin.x.max(content_origin.x);
 8811
 8812        let max_x = content_origin.x + editor_width - size.width;
 8813
 8814        if origin.x > max_x {
 8815            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8816
 8817            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8818                origin.y += offset;
 8819                IconName::ArrowUp
 8820            } else {
 8821                origin.y -= offset;
 8822                IconName::ArrowDown
 8823            };
 8824
 8825            element = self
 8826                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8827                .into_any();
 8828
 8829            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8830
 8831            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8832        }
 8833
 8834        element.prepaint_at(origin, window, cx);
 8835        Some((element, origin))
 8836    }
 8837
 8838    fn render_edit_prediction_diff_popover(
 8839        self: &Editor,
 8840        text_bounds: &Bounds<Pixels>,
 8841        content_origin: gpui::Point<Pixels>,
 8842        right_margin: Pixels,
 8843        editor_snapshot: &EditorSnapshot,
 8844        visible_row_range: Range<DisplayRow>,
 8845        line_layouts: &[LineWithInvisibles],
 8846        line_height: Pixels,
 8847        scroll_pixel_position: gpui::Point<Pixels>,
 8848        newest_selection_head: Option<DisplayPoint>,
 8849        editor_width: Pixels,
 8850        style: &EditorStyle,
 8851        edits: &Vec<(Range<Anchor>, String)>,
 8852        edit_preview: &Option<language::EditPreview>,
 8853        snapshot: &language::BufferSnapshot,
 8854        window: &mut Window,
 8855        cx: &mut App,
 8856    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8857        let edit_start = edits
 8858            .first()
 8859            .unwrap()
 8860            .0
 8861            .start
 8862            .to_display_point(editor_snapshot);
 8863        let edit_end = edits
 8864            .last()
 8865            .unwrap()
 8866            .0
 8867            .end
 8868            .to_display_point(editor_snapshot);
 8869
 8870        let is_visible = visible_row_range.contains(&edit_start.row())
 8871            || visible_row_range.contains(&edit_end.row());
 8872        if !is_visible {
 8873            return None;
 8874        }
 8875
 8876        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8877            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8878        } else {
 8879            // Fallback for providers without edit_preview
 8880            crate::edit_prediction_fallback_text(edits, cx)
 8881        };
 8882
 8883        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8884        let line_count = highlighted_edits.text.lines().count();
 8885
 8886        const BORDER_WIDTH: Pixels = px(1.);
 8887
 8888        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8889        let has_keybind = keybind.is_some();
 8890
 8891        let mut element = h_flex()
 8892            .items_start()
 8893            .child(
 8894                h_flex()
 8895                    .bg(cx.theme().colors().editor_background)
 8896                    .border(BORDER_WIDTH)
 8897                    .shadow_xs()
 8898                    .border_color(cx.theme().colors().border)
 8899                    .rounded_l_lg()
 8900                    .when(line_count > 1, |el| el.rounded_br_lg())
 8901                    .pr_1()
 8902                    .child(styled_text),
 8903            )
 8904            .child(
 8905                h_flex()
 8906                    .h(line_height + BORDER_WIDTH * 2.)
 8907                    .px_1p5()
 8908                    .gap_1()
 8909                    // Workaround: For some reason, there's a gap if we don't do this
 8910                    .ml(-BORDER_WIDTH)
 8911                    .shadow(vec![gpui::BoxShadow {
 8912                        color: gpui::black().opacity(0.05),
 8913                        offset: point(px(1.), px(1.)),
 8914                        blur_radius: px(2.),
 8915                        spread_radius: px(0.),
 8916                    }])
 8917                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8918                    .border(BORDER_WIDTH)
 8919                    .border_color(cx.theme().colors().border)
 8920                    .rounded_r_lg()
 8921                    .id("edit_prediction_diff_popover_keybind")
 8922                    .when(!has_keybind, |el| {
 8923                        let status_colors = cx.theme().status();
 8924
 8925                        el.bg(status_colors.error_background)
 8926                            .border_color(status_colors.error.opacity(0.6))
 8927                            .child(Icon::new(IconName::Info).color(Color::Error))
 8928                            .cursor_default()
 8929                            .hoverable_tooltip(move |_window, cx| {
 8930                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8931                            })
 8932                    })
 8933                    .children(keybind),
 8934            )
 8935            .into_any();
 8936
 8937        let longest_row =
 8938            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8939        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8940            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8941        } else {
 8942            layout_line(
 8943                longest_row,
 8944                editor_snapshot,
 8945                style,
 8946                editor_width,
 8947                |_| false,
 8948                window,
 8949                cx,
 8950            )
 8951            .width
 8952        };
 8953
 8954        let viewport_bounds =
 8955            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8956                right: -right_margin,
 8957                ..Default::default()
 8958            });
 8959
 8960        let x_after_longest =
 8961            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8962                - scroll_pixel_position.x;
 8963
 8964        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8965
 8966        // Fully visible if it can be displayed within the window (allow overlapping other
 8967        // panes). However, this is only allowed if the popover starts within text_bounds.
 8968        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8969            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8970
 8971        let mut origin = if can_position_to_the_right {
 8972            point(
 8973                x_after_longest,
 8974                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8975                    - scroll_pixel_position.y,
 8976            )
 8977        } else {
 8978            let cursor_row = newest_selection_head.map(|head| head.row());
 8979            let above_edit = edit_start
 8980                .row()
 8981                .0
 8982                .checked_sub(line_count as u32)
 8983                .map(DisplayRow);
 8984            let below_edit = Some(edit_end.row() + 1);
 8985            let above_cursor =
 8986                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8987            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8988
 8989            // Place the edit popover adjacent to the edit if there is a location
 8990            // available that is onscreen and does not obscure the cursor. Otherwise,
 8991            // place it adjacent to the cursor.
 8992            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8993                .into_iter()
 8994                .flatten()
 8995                .find(|&start_row| {
 8996                    let end_row = start_row + line_count as u32;
 8997                    visible_row_range.contains(&start_row)
 8998                        && visible_row_range.contains(&end_row)
 8999                        && cursor_row
 9000                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9001                })?;
 9002
 9003            content_origin
 9004                + point(
 9005                    -scroll_pixel_position.x,
 9006                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9007                )
 9008        };
 9009
 9010        origin.x -= BORDER_WIDTH;
 9011
 9012        window.defer_draw(element, origin, 1);
 9013
 9014        // Do not return an element, since it will already be drawn due to defer_draw.
 9015        None
 9016    }
 9017
 9018    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9019        px(30.)
 9020    }
 9021
 9022    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9023        if self.read_only(cx) {
 9024            cx.theme().players().read_only()
 9025        } else {
 9026            self.style.as_ref().unwrap().local_player
 9027        }
 9028    }
 9029
 9030    fn render_edit_prediction_accept_keybind(
 9031        &self,
 9032        window: &mut Window,
 9033        cx: &App,
 9034    ) -> Option<AnyElement> {
 9035        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9036        let accept_keystroke = accept_binding.keystroke()?;
 9037
 9038        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9039
 9040        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 9041            Color::Accent
 9042        } else {
 9043            Color::Muted
 9044        };
 9045
 9046        h_flex()
 9047            .px_0p5()
 9048            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9049            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9050            .text_size(TextSize::XSmall.rems(cx))
 9051            .child(h_flex().children(ui::render_modifiers(
 9052                &accept_keystroke.modifiers,
 9053                PlatformStyle::platform(),
 9054                Some(modifiers_color),
 9055                Some(IconSize::XSmall.rems().into()),
 9056                true,
 9057            )))
 9058            .when(is_platform_style_mac, |parent| {
 9059                parent.child(accept_keystroke.key.clone())
 9060            })
 9061            .when(!is_platform_style_mac, |parent| {
 9062                parent.child(
 9063                    Key::new(
 9064                        util::capitalize(&accept_keystroke.key),
 9065                        Some(Color::Default),
 9066                    )
 9067                    .size(Some(IconSize::XSmall.rems().into())),
 9068                )
 9069            })
 9070            .into_any()
 9071            .into()
 9072    }
 9073
 9074    fn render_edit_prediction_line_popover(
 9075        &self,
 9076        label: impl Into<SharedString>,
 9077        icon: Option<IconName>,
 9078        window: &mut Window,
 9079        cx: &App,
 9080    ) -> Option<Stateful<Div>> {
 9081        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9082
 9083        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9084        let has_keybind = keybind.is_some();
 9085
 9086        let result = h_flex()
 9087            .id("ep-line-popover")
 9088            .py_0p5()
 9089            .pl_1()
 9090            .pr(padding_right)
 9091            .gap_1()
 9092            .rounded_md()
 9093            .border_1()
 9094            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9095            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9096            .shadow_xs()
 9097            .when(!has_keybind, |el| {
 9098                let status_colors = cx.theme().status();
 9099
 9100                el.bg(status_colors.error_background)
 9101                    .border_color(status_colors.error.opacity(0.6))
 9102                    .pl_2()
 9103                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9104                    .cursor_default()
 9105                    .hoverable_tooltip(move |_window, cx| {
 9106                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9107                    })
 9108            })
 9109            .children(keybind)
 9110            .child(
 9111                Label::new(label)
 9112                    .size(LabelSize::Small)
 9113                    .when(!has_keybind, |el| {
 9114                        el.color(cx.theme().status().error.into()).strikethrough()
 9115                    }),
 9116            )
 9117            .when(!has_keybind, |el| {
 9118                el.child(
 9119                    h_flex().ml_1().child(
 9120                        Icon::new(IconName::Info)
 9121                            .size(IconSize::Small)
 9122                            .color(cx.theme().status().error.into()),
 9123                    ),
 9124                )
 9125            })
 9126            .when_some(icon, |element, icon| {
 9127                element.child(
 9128                    div()
 9129                        .mt(px(1.5))
 9130                        .child(Icon::new(icon).size(IconSize::Small)),
 9131                )
 9132            });
 9133
 9134        Some(result)
 9135    }
 9136
 9137    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9138        let accent_color = cx.theme().colors().text_accent;
 9139        let editor_bg_color = cx.theme().colors().editor_background;
 9140        editor_bg_color.blend(accent_color.opacity(0.1))
 9141    }
 9142
 9143    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9144        let accent_color = cx.theme().colors().text_accent;
 9145        let editor_bg_color = cx.theme().colors().editor_background;
 9146        editor_bg_color.blend(accent_color.opacity(0.6))
 9147    }
 9148    fn get_prediction_provider_icon_name(
 9149        provider: &Option<RegisteredEditPredictionProvider>,
 9150    ) -> IconName {
 9151        match provider {
 9152            Some(provider) => match provider.provider.name() {
 9153                "copilot" => IconName::Copilot,
 9154                "supermaven" => IconName::Supermaven,
 9155                _ => IconName::ZedPredict,
 9156            },
 9157            None => IconName::ZedPredict,
 9158        }
 9159    }
 9160
 9161    fn render_edit_prediction_cursor_popover(
 9162        &self,
 9163        min_width: Pixels,
 9164        max_width: Pixels,
 9165        cursor_point: Point,
 9166        style: &EditorStyle,
 9167        accept_keystroke: Option<&gpui::Keystroke>,
 9168        _window: &Window,
 9169        cx: &mut Context<Editor>,
 9170    ) -> Option<AnyElement> {
 9171        let provider = self.edit_prediction_provider.as_ref()?;
 9172        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9173
 9174        if provider.provider.needs_terms_acceptance(cx) {
 9175            return Some(
 9176                h_flex()
 9177                    .min_w(min_width)
 9178                    .flex_1()
 9179                    .px_2()
 9180                    .py_1()
 9181                    .gap_3()
 9182                    .elevation_2(cx)
 9183                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9184                    .id("accept-terms")
 9185                    .cursor_pointer()
 9186                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9187                    .on_click(cx.listener(|this, _event, window, cx| {
 9188                        cx.stop_propagation();
 9189                        this.report_editor_event(ReportEditorEvent::ZetaTosClicked, None, cx);
 9190                        window.dispatch_action(
 9191                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9192                            cx,
 9193                        );
 9194                    }))
 9195                    .child(
 9196                        h_flex()
 9197                            .flex_1()
 9198                            .gap_2()
 9199                            .child(Icon::new(provider_icon))
 9200                            .child(Label::new("Accept Terms of Service"))
 9201                            .child(div().w_full())
 9202                            .child(
 9203                                Icon::new(IconName::ArrowUpRight)
 9204                                    .color(Color::Muted)
 9205                                    .size(IconSize::Small),
 9206                            )
 9207                            .into_any_element(),
 9208                    )
 9209                    .into_any(),
 9210            );
 9211        }
 9212
 9213        let is_refreshing = provider.provider.is_refreshing(cx);
 9214
 9215        fn pending_completion_container(icon: IconName) -> Div {
 9216            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9217        }
 9218
 9219        let completion = match &self.active_edit_prediction {
 9220            Some(prediction) => {
 9221                if !self.has_visible_completions_menu() {
 9222                    const RADIUS: Pixels = px(6.);
 9223                    const BORDER_WIDTH: Pixels = px(1.);
 9224
 9225                    return Some(
 9226                        h_flex()
 9227                            .elevation_2(cx)
 9228                            .border(BORDER_WIDTH)
 9229                            .border_color(cx.theme().colors().border)
 9230                            .when(accept_keystroke.is_none(), |el| {
 9231                                el.border_color(cx.theme().status().error)
 9232                            })
 9233                            .rounded(RADIUS)
 9234                            .rounded_tl(px(0.))
 9235                            .overflow_hidden()
 9236                            .child(div().px_1p5().child(match &prediction.completion {
 9237                                EditPrediction::Move { target, snapshot } => {
 9238                                    use text::ToPoint as _;
 9239                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9240                                    {
 9241                                        Icon::new(IconName::ZedPredictDown)
 9242                                    } else {
 9243                                        Icon::new(IconName::ZedPredictUp)
 9244                                    }
 9245                                }
 9246                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9247                            }))
 9248                            .child(
 9249                                h_flex()
 9250                                    .gap_1()
 9251                                    .py_1()
 9252                                    .px_2()
 9253                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9254                                    .border_l_1()
 9255                                    .border_color(cx.theme().colors().border)
 9256                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9257                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9258                                        el.child(
 9259                                            Label::new("Hold")
 9260                                                .size(LabelSize::Small)
 9261                                                .when(accept_keystroke.is_none(), |el| {
 9262                                                    el.strikethrough()
 9263                                                })
 9264                                                .line_height_style(LineHeightStyle::UiLabel),
 9265                                        )
 9266                                    })
 9267                                    .id("edit_prediction_cursor_popover_keybind")
 9268                                    .when(accept_keystroke.is_none(), |el| {
 9269                                        let status_colors = cx.theme().status();
 9270
 9271                                        el.bg(status_colors.error_background)
 9272                                            .border_color(status_colors.error.opacity(0.6))
 9273                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9274                                            .cursor_default()
 9275                                            .hoverable_tooltip(move |_window, cx| {
 9276                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9277                                                    .into()
 9278                                            })
 9279                                    })
 9280                                    .when_some(
 9281                                        accept_keystroke.as_ref(),
 9282                                        |el, accept_keystroke| {
 9283                                            el.child(h_flex().children(ui::render_modifiers(
 9284                                                &accept_keystroke.modifiers,
 9285                                                PlatformStyle::platform(),
 9286                                                Some(Color::Default),
 9287                                                Some(IconSize::XSmall.rems().into()),
 9288                                                false,
 9289                                            )))
 9290                                        },
 9291                                    ),
 9292                            )
 9293                            .into_any(),
 9294                    );
 9295                }
 9296
 9297                self.render_edit_prediction_cursor_popover_preview(
 9298                    prediction,
 9299                    cursor_point,
 9300                    style,
 9301                    cx,
 9302                )?
 9303            }
 9304
 9305            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9306                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9307                    stale_completion,
 9308                    cursor_point,
 9309                    style,
 9310                    cx,
 9311                )?,
 9312
 9313                None => pending_completion_container(provider_icon)
 9314                    .child(Label::new("...").size(LabelSize::Small)),
 9315            },
 9316
 9317            None => pending_completion_container(provider_icon)
 9318                .child(Label::new("...").size(LabelSize::Small)),
 9319        };
 9320
 9321        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9322            completion
 9323                .with_animation(
 9324                    "loading-completion",
 9325                    Animation::new(Duration::from_secs(2))
 9326                        .repeat()
 9327                        .with_easing(pulsating_between(0.4, 0.8)),
 9328                    |label, delta| label.opacity(delta),
 9329                )
 9330                .into_any_element()
 9331        } else {
 9332            completion.into_any_element()
 9333        };
 9334
 9335        let has_completion = self.active_edit_prediction.is_some();
 9336
 9337        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9338        Some(
 9339            h_flex()
 9340                .min_w(min_width)
 9341                .max_w(max_width)
 9342                .flex_1()
 9343                .elevation_2(cx)
 9344                .border_color(cx.theme().colors().border)
 9345                .child(
 9346                    div()
 9347                        .flex_1()
 9348                        .py_1()
 9349                        .px_2()
 9350                        .overflow_hidden()
 9351                        .child(completion),
 9352                )
 9353                .when_some(accept_keystroke, |el, accept_keystroke| {
 9354                    if !accept_keystroke.modifiers.modified() {
 9355                        return el;
 9356                    }
 9357
 9358                    el.child(
 9359                        h_flex()
 9360                            .h_full()
 9361                            .border_l_1()
 9362                            .rounded_r_lg()
 9363                            .border_color(cx.theme().colors().border)
 9364                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9365                            .gap_1()
 9366                            .py_1()
 9367                            .px_2()
 9368                            .child(
 9369                                h_flex()
 9370                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9371                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9372                                    .child(h_flex().children(ui::render_modifiers(
 9373                                        &accept_keystroke.modifiers,
 9374                                        PlatformStyle::platform(),
 9375                                        Some(if !has_completion {
 9376                                            Color::Muted
 9377                                        } else {
 9378                                            Color::Default
 9379                                        }),
 9380                                        None,
 9381                                        false,
 9382                                    ))),
 9383                            )
 9384                            .child(Label::new("Preview").into_any_element())
 9385                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9386                    )
 9387                })
 9388                .into_any(),
 9389        )
 9390    }
 9391
 9392    fn render_edit_prediction_cursor_popover_preview(
 9393        &self,
 9394        completion: &EditPredictionState,
 9395        cursor_point: Point,
 9396        style: &EditorStyle,
 9397        cx: &mut Context<Editor>,
 9398    ) -> Option<Div> {
 9399        use text::ToPoint as _;
 9400
 9401        fn render_relative_row_jump(
 9402            prefix: impl Into<String>,
 9403            current_row: u32,
 9404            target_row: u32,
 9405        ) -> Div {
 9406            let (row_diff, arrow) = if target_row < current_row {
 9407                (current_row - target_row, IconName::ArrowUp)
 9408            } else {
 9409                (target_row - current_row, IconName::ArrowDown)
 9410            };
 9411
 9412            h_flex()
 9413                .child(
 9414                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9415                        .color(Color::Muted)
 9416                        .size(LabelSize::Small),
 9417                )
 9418                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9419        }
 9420
 9421        let supports_jump = self
 9422            .edit_prediction_provider
 9423            .as_ref()
 9424            .map(|provider| provider.provider.supports_jump_to_edit())
 9425            .unwrap_or(true);
 9426
 9427        match &completion.completion {
 9428            EditPrediction::Move {
 9429                target, snapshot, ..
 9430            } => {
 9431                if !supports_jump {
 9432                    return None;
 9433                }
 9434
 9435                Some(
 9436                    h_flex()
 9437                        .px_2()
 9438                        .gap_2()
 9439                        .flex_1()
 9440                        .child(
 9441                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9442                                Icon::new(IconName::ZedPredictDown)
 9443                            } else {
 9444                                Icon::new(IconName::ZedPredictUp)
 9445                            },
 9446                        )
 9447                        .child(Label::new("Jump to Edit")),
 9448                )
 9449            }
 9450
 9451            EditPrediction::Edit {
 9452                edits,
 9453                edit_preview,
 9454                snapshot,
 9455                display_mode: _,
 9456            } => {
 9457                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9458
 9459                let (highlighted_edits, has_more_lines) =
 9460                    if let Some(edit_preview) = edit_preview.as_ref() {
 9461                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9462                            .first_line_preview()
 9463                    } else {
 9464                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9465                    };
 9466
 9467                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9468                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9469
 9470                let preview = h_flex()
 9471                    .gap_1()
 9472                    .min_w_16()
 9473                    .child(styled_text)
 9474                    .when(has_more_lines, |parent| parent.child(""));
 9475
 9476                let left = if supports_jump && first_edit_row != cursor_point.row {
 9477                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9478                        .into_any_element()
 9479                } else {
 9480                    let icon_name =
 9481                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9482                    Icon::new(icon_name).into_any_element()
 9483                };
 9484
 9485                Some(
 9486                    h_flex()
 9487                        .h_full()
 9488                        .flex_1()
 9489                        .gap_2()
 9490                        .pr_1()
 9491                        .overflow_x_hidden()
 9492                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9493                        .child(left)
 9494                        .child(preview),
 9495                )
 9496            }
 9497        }
 9498    }
 9499
 9500    pub fn render_context_menu(
 9501        &self,
 9502        style: &EditorStyle,
 9503        max_height_in_lines: u32,
 9504        window: &mut Window,
 9505        cx: &mut Context<Editor>,
 9506    ) -> Option<AnyElement> {
 9507        let menu = self.context_menu.borrow();
 9508        let menu = menu.as_ref()?;
 9509        if !menu.visible() {
 9510            return None;
 9511        };
 9512        Some(menu.render(style, max_height_in_lines, window, cx))
 9513    }
 9514
 9515    fn render_context_menu_aside(
 9516        &mut self,
 9517        max_size: Size<Pixels>,
 9518        window: &mut Window,
 9519        cx: &mut Context<Editor>,
 9520    ) -> Option<AnyElement> {
 9521        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9522            if menu.visible() {
 9523                menu.render_aside(max_size, window, cx)
 9524            } else {
 9525                None
 9526            }
 9527        })
 9528    }
 9529
 9530    fn hide_context_menu(
 9531        &mut self,
 9532        window: &mut Window,
 9533        cx: &mut Context<Self>,
 9534    ) -> Option<CodeContextMenu> {
 9535        cx.notify();
 9536        self.completion_tasks.clear();
 9537        let context_menu = self.context_menu.borrow_mut().take();
 9538        self.stale_edit_prediction_in_menu.take();
 9539        self.update_visible_edit_prediction(window, cx);
 9540        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9541            && let Some(completion_provider) = &self.completion_provider
 9542        {
 9543            completion_provider.selection_changed(None, window, cx);
 9544        }
 9545        context_menu
 9546    }
 9547
 9548    fn show_snippet_choices(
 9549        &mut self,
 9550        choices: &Vec<String>,
 9551        selection: Range<Anchor>,
 9552        cx: &mut Context<Self>,
 9553    ) {
 9554        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9555            (Some(a), Some(b)) if a == b => a,
 9556            _ => {
 9557                log::error!("expected anchor range to have matching buffer IDs");
 9558                return;
 9559            }
 9560        };
 9561        let multi_buffer = self.buffer().read(cx);
 9562        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9563            return;
 9564        };
 9565
 9566        let id = post_inc(&mut self.next_completion_id);
 9567        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9568        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9569            CompletionsMenu::new_snippet_choices(
 9570                id,
 9571                true,
 9572                choices,
 9573                selection,
 9574                buffer,
 9575                snippet_sort_order,
 9576            ),
 9577        ));
 9578    }
 9579
 9580    pub fn insert_snippet(
 9581        &mut self,
 9582        insertion_ranges: &[Range<usize>],
 9583        snippet: Snippet,
 9584        window: &mut Window,
 9585        cx: &mut Context<Self>,
 9586    ) -> Result<()> {
 9587        struct Tabstop<T> {
 9588            is_end_tabstop: bool,
 9589            ranges: Vec<Range<T>>,
 9590            choices: Option<Vec<String>>,
 9591        }
 9592
 9593        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9594            let snippet_text: Arc<str> = snippet.text.clone().into();
 9595            let edits = insertion_ranges
 9596                .iter()
 9597                .cloned()
 9598                .map(|range| (range, snippet_text.clone()));
 9599            let autoindent_mode = AutoindentMode::Block {
 9600                original_indent_columns: Vec::new(),
 9601            };
 9602            buffer.edit(edits, Some(autoindent_mode), cx);
 9603
 9604            let snapshot = &*buffer.read(cx);
 9605            let snippet = &snippet;
 9606            snippet
 9607                .tabstops
 9608                .iter()
 9609                .map(|tabstop| {
 9610                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9611                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9612                    });
 9613                    let mut tabstop_ranges = tabstop
 9614                        .ranges
 9615                        .iter()
 9616                        .flat_map(|tabstop_range| {
 9617                            let mut delta = 0_isize;
 9618                            insertion_ranges.iter().map(move |insertion_range| {
 9619                                let insertion_start = insertion_range.start as isize + delta;
 9620                                delta +=
 9621                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9622
 9623                                let start = ((insertion_start + tabstop_range.start) as usize)
 9624                                    .min(snapshot.len());
 9625                                let end = ((insertion_start + tabstop_range.end) as usize)
 9626                                    .min(snapshot.len());
 9627                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9628                            })
 9629                        })
 9630                        .collect::<Vec<_>>();
 9631                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9632
 9633                    Tabstop {
 9634                        is_end_tabstop,
 9635                        ranges: tabstop_ranges,
 9636                        choices: tabstop.choices.clone(),
 9637                    }
 9638                })
 9639                .collect::<Vec<_>>()
 9640        });
 9641        if let Some(tabstop) = tabstops.first() {
 9642            self.change_selections(Default::default(), window, cx, |s| {
 9643                // Reverse order so that the first range is the newest created selection.
 9644                // Completions will use it and autoscroll will prioritize it.
 9645                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9646            });
 9647
 9648            if let Some(choices) = &tabstop.choices
 9649                && let Some(selection) = tabstop.ranges.first()
 9650            {
 9651                self.show_snippet_choices(choices, selection.clone(), cx)
 9652            }
 9653
 9654            // If we're already at the last tabstop and it's at the end of the snippet,
 9655            // we're done, we don't need to keep the state around.
 9656            if !tabstop.is_end_tabstop {
 9657                let choices = tabstops
 9658                    .iter()
 9659                    .map(|tabstop| tabstop.choices.clone())
 9660                    .collect();
 9661
 9662                let ranges = tabstops
 9663                    .into_iter()
 9664                    .map(|tabstop| tabstop.ranges)
 9665                    .collect::<Vec<_>>();
 9666
 9667                self.snippet_stack.push(SnippetState {
 9668                    active_index: 0,
 9669                    ranges,
 9670                    choices,
 9671                });
 9672            }
 9673
 9674            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9675            if self.autoclose_regions.is_empty() {
 9676                let snapshot = self.buffer.read(cx).snapshot(cx);
 9677                let mut all_selections = self.selections.all::<Point>(cx);
 9678                for selection in &mut all_selections {
 9679                    let selection_head = selection.head();
 9680                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9681                        continue;
 9682                    };
 9683
 9684                    let mut bracket_pair = None;
 9685                    let max_lookup_length = scope
 9686                        .brackets()
 9687                        .map(|(pair, _)| {
 9688                            pair.start
 9689                                .as_str()
 9690                                .chars()
 9691                                .count()
 9692                                .max(pair.end.as_str().chars().count())
 9693                        })
 9694                        .max();
 9695                    if let Some(max_lookup_length) = max_lookup_length {
 9696                        let next_text = snapshot
 9697                            .chars_at(selection_head)
 9698                            .take(max_lookup_length)
 9699                            .collect::<String>();
 9700                        let prev_text = snapshot
 9701                            .reversed_chars_at(selection_head)
 9702                            .take(max_lookup_length)
 9703                            .collect::<String>();
 9704
 9705                        for (pair, enabled) in scope.brackets() {
 9706                            if enabled
 9707                                && pair.close
 9708                                && prev_text.starts_with(pair.start.as_str())
 9709                                && next_text.starts_with(pair.end.as_str())
 9710                            {
 9711                                bracket_pair = Some(pair.clone());
 9712                                break;
 9713                            }
 9714                        }
 9715                    }
 9716
 9717                    if let Some(pair) = bracket_pair {
 9718                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9719                        let autoclose_enabled =
 9720                            self.use_autoclose && snapshot_settings.use_autoclose;
 9721                        if autoclose_enabled {
 9722                            let start = snapshot.anchor_after(selection_head);
 9723                            let end = snapshot.anchor_after(selection_head);
 9724                            self.autoclose_regions.push(AutocloseRegion {
 9725                                selection_id: selection.id,
 9726                                range: start..end,
 9727                                pair,
 9728                            });
 9729                        }
 9730                    }
 9731                }
 9732            }
 9733        }
 9734        Ok(())
 9735    }
 9736
 9737    pub fn move_to_next_snippet_tabstop(
 9738        &mut self,
 9739        window: &mut Window,
 9740        cx: &mut Context<Self>,
 9741    ) -> bool {
 9742        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9743    }
 9744
 9745    pub fn move_to_prev_snippet_tabstop(
 9746        &mut self,
 9747        window: &mut Window,
 9748        cx: &mut Context<Self>,
 9749    ) -> bool {
 9750        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9751    }
 9752
 9753    pub fn move_to_snippet_tabstop(
 9754        &mut self,
 9755        bias: Bias,
 9756        window: &mut Window,
 9757        cx: &mut Context<Self>,
 9758    ) -> bool {
 9759        if let Some(mut snippet) = self.snippet_stack.pop() {
 9760            match bias {
 9761                Bias::Left => {
 9762                    if snippet.active_index > 0 {
 9763                        snippet.active_index -= 1;
 9764                    } else {
 9765                        self.snippet_stack.push(snippet);
 9766                        return false;
 9767                    }
 9768                }
 9769                Bias::Right => {
 9770                    if snippet.active_index + 1 < snippet.ranges.len() {
 9771                        snippet.active_index += 1;
 9772                    } else {
 9773                        self.snippet_stack.push(snippet);
 9774                        return false;
 9775                    }
 9776                }
 9777            }
 9778            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9779                self.change_selections(Default::default(), window, cx, |s| {
 9780                    // Reverse order so that the first range is the newest created selection.
 9781                    // Completions will use it and autoscroll will prioritize it.
 9782                    s.select_ranges(current_ranges.iter().rev().cloned())
 9783                });
 9784
 9785                if let Some(choices) = &snippet.choices[snippet.active_index]
 9786                    && let Some(selection) = current_ranges.first()
 9787                {
 9788                    self.show_snippet_choices(choices, selection.clone(), cx);
 9789                }
 9790
 9791                // If snippet state is not at the last tabstop, push it back on the stack
 9792                if snippet.active_index + 1 < snippet.ranges.len() {
 9793                    self.snippet_stack.push(snippet);
 9794                }
 9795                return true;
 9796            }
 9797        }
 9798
 9799        false
 9800    }
 9801
 9802    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9803        self.transact(window, cx, |this, window, cx| {
 9804            this.select_all(&SelectAll, window, cx);
 9805            this.insert("", window, cx);
 9806        });
 9807    }
 9808
 9809    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9810        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9811        self.transact(window, cx, |this, window, cx| {
 9812            this.select_autoclose_pair(window, cx);
 9813            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9814            if !this.linked_edit_ranges.is_empty() {
 9815                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9816                let snapshot = this.buffer.read(cx).snapshot(cx);
 9817
 9818                for selection in selections.iter() {
 9819                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9820                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9821                    if selection_start.buffer_id != selection_end.buffer_id {
 9822                        continue;
 9823                    }
 9824                    if let Some(ranges) =
 9825                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9826                    {
 9827                        for (buffer, entries) in ranges {
 9828                            linked_ranges.entry(buffer).or_default().extend(entries);
 9829                        }
 9830                    }
 9831                }
 9832            }
 9833
 9834            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9835            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9836            for selection in &mut selections {
 9837                if selection.is_empty() {
 9838                    let old_head = selection.head();
 9839                    let mut new_head =
 9840                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9841                            .to_point(&display_map);
 9842                    if let Some((buffer, line_buffer_range)) = display_map
 9843                        .buffer_snapshot
 9844                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9845                    {
 9846                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9847                        let indent_len = match indent_size.kind {
 9848                            IndentKind::Space => {
 9849                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9850                            }
 9851                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9852                        };
 9853                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9854                            let indent_len = indent_len.get();
 9855                            new_head = cmp::min(
 9856                                new_head,
 9857                                MultiBufferPoint::new(
 9858                                    old_head.row,
 9859                                    ((old_head.column - 1) / indent_len) * indent_len,
 9860                                ),
 9861                            );
 9862                        }
 9863                    }
 9864
 9865                    selection.set_head(new_head, SelectionGoal::None);
 9866                }
 9867            }
 9868
 9869            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9870            this.insert("", window, cx);
 9871            let empty_str: Arc<str> = Arc::from("");
 9872            for (buffer, edits) in linked_ranges {
 9873                let snapshot = buffer.read(cx).snapshot();
 9874                use text::ToPoint as TP;
 9875
 9876                let edits = edits
 9877                    .into_iter()
 9878                    .map(|range| {
 9879                        let end_point = TP::to_point(&range.end, &snapshot);
 9880                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9881
 9882                        if end_point == start_point {
 9883                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9884                                .saturating_sub(1);
 9885                            start_point =
 9886                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9887                        };
 9888
 9889                        (start_point..end_point, empty_str.clone())
 9890                    })
 9891                    .sorted_by_key(|(range, _)| range.start)
 9892                    .collect::<Vec<_>>();
 9893                buffer.update(cx, |this, cx| {
 9894                    this.edit(edits, None, cx);
 9895                })
 9896            }
 9897            this.refresh_edit_prediction(true, false, window, cx);
 9898            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9899        });
 9900    }
 9901
 9902    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9903        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9904        self.transact(window, cx, |this, window, cx| {
 9905            this.change_selections(Default::default(), window, cx, |s| {
 9906                s.move_with(|map, selection| {
 9907                    if selection.is_empty() {
 9908                        let cursor = movement::right(map, selection.head());
 9909                        selection.end = cursor;
 9910                        selection.reversed = true;
 9911                        selection.goal = SelectionGoal::None;
 9912                    }
 9913                })
 9914            });
 9915            this.insert("", window, cx);
 9916            this.refresh_edit_prediction(true, false, window, cx);
 9917        });
 9918    }
 9919
 9920    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9921        if self.mode.is_single_line() {
 9922            cx.propagate();
 9923            return;
 9924        }
 9925
 9926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9927        if self.move_to_prev_snippet_tabstop(window, cx) {
 9928            return;
 9929        }
 9930        self.outdent(&Outdent, window, cx);
 9931    }
 9932
 9933    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9934        if self.mode.is_single_line() {
 9935            cx.propagate();
 9936            return;
 9937        }
 9938
 9939        if self.move_to_next_snippet_tabstop(window, cx) {
 9940            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9941            return;
 9942        }
 9943        if self.read_only(cx) {
 9944            return;
 9945        }
 9946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9947        let mut selections = self.selections.all_adjusted(cx);
 9948        let buffer = self.buffer.read(cx);
 9949        let snapshot = buffer.snapshot(cx);
 9950        let rows_iter = selections.iter().map(|s| s.head().row);
 9951        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9952
 9953        let has_some_cursor_in_whitespace = selections
 9954            .iter()
 9955            .filter(|selection| selection.is_empty())
 9956            .any(|selection| {
 9957                let cursor = selection.head();
 9958                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9959                cursor.column < current_indent.len
 9960            });
 9961
 9962        let mut edits = Vec::new();
 9963        let mut prev_edited_row = 0;
 9964        let mut row_delta = 0;
 9965        for selection in &mut selections {
 9966            if selection.start.row != prev_edited_row {
 9967                row_delta = 0;
 9968            }
 9969            prev_edited_row = selection.end.row;
 9970
 9971            // If the selection is non-empty, then increase the indentation of the selected lines.
 9972            if !selection.is_empty() {
 9973                row_delta =
 9974                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9975                continue;
 9976            }
 9977
 9978            let cursor = selection.head();
 9979            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9980            if let Some(suggested_indent) =
 9981                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9982            {
 9983                // Don't do anything if already at suggested indent
 9984                // and there is any other cursor which is not
 9985                if has_some_cursor_in_whitespace
 9986                    && cursor.column == current_indent.len
 9987                    && current_indent.len == suggested_indent.len
 9988                {
 9989                    continue;
 9990                }
 9991
 9992                // Adjust line and move cursor to suggested indent
 9993                // if cursor is not at suggested indent
 9994                if cursor.column < suggested_indent.len
 9995                    && cursor.column <= current_indent.len
 9996                    && current_indent.len <= suggested_indent.len
 9997                {
 9998                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9999                    selection.end = selection.start;
10000                    if row_delta == 0 {
10001                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10002                            cursor.row,
10003                            current_indent,
10004                            suggested_indent,
10005                        ));
10006                        row_delta = suggested_indent.len - current_indent.len;
10007                    }
10008                    continue;
10009                }
10010
10011                // If current indent is more than suggested indent
10012                // only move cursor to current indent and skip indent
10013                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10014                    selection.start = Point::new(cursor.row, current_indent.len);
10015                    selection.end = selection.start;
10016                    continue;
10017                }
10018            }
10019
10020            // Otherwise, insert a hard or soft tab.
10021            let settings = buffer.language_settings_at(cursor, cx);
10022            let tab_size = if settings.hard_tabs {
10023                IndentSize::tab()
10024            } else {
10025                let tab_size = settings.tab_size.get();
10026                let indent_remainder = snapshot
10027                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10028                    .flat_map(str::chars)
10029                    .fold(row_delta % tab_size, |counter: u32, c| {
10030                        if c == '\t' {
10031                            0
10032                        } else {
10033                            (counter + 1) % tab_size
10034                        }
10035                    });
10036
10037                let chars_to_next_tab_stop = tab_size - indent_remainder;
10038                IndentSize::spaces(chars_to_next_tab_stop)
10039            };
10040            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10041            selection.end = selection.start;
10042            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10043            row_delta += tab_size.len;
10044        }
10045
10046        self.transact(window, cx, |this, window, cx| {
10047            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10048            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10049            this.refresh_edit_prediction(true, false, window, cx);
10050        });
10051    }
10052
10053    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10054        if self.read_only(cx) {
10055            return;
10056        }
10057        if self.mode.is_single_line() {
10058            cx.propagate();
10059            return;
10060        }
10061
10062        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10063        let mut selections = self.selections.all::<Point>(cx);
10064        let mut prev_edited_row = 0;
10065        let mut row_delta = 0;
10066        let mut edits = Vec::new();
10067        let buffer = self.buffer.read(cx);
10068        let snapshot = buffer.snapshot(cx);
10069        for selection in &mut selections {
10070            if selection.start.row != prev_edited_row {
10071                row_delta = 0;
10072            }
10073            prev_edited_row = selection.end.row;
10074
10075            row_delta =
10076                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10077        }
10078
10079        self.transact(window, cx, |this, window, cx| {
10080            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10081            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10082        });
10083    }
10084
10085    fn indent_selection(
10086        buffer: &MultiBuffer,
10087        snapshot: &MultiBufferSnapshot,
10088        selection: &mut Selection<Point>,
10089        edits: &mut Vec<(Range<Point>, String)>,
10090        delta_for_start_row: u32,
10091        cx: &App,
10092    ) -> u32 {
10093        let settings = buffer.language_settings_at(selection.start, cx);
10094        let tab_size = settings.tab_size.get();
10095        let indent_kind = if settings.hard_tabs {
10096            IndentKind::Tab
10097        } else {
10098            IndentKind::Space
10099        };
10100        let mut start_row = selection.start.row;
10101        let mut end_row = selection.end.row + 1;
10102
10103        // If a selection ends at the beginning of a line, don't indent
10104        // that last line.
10105        if selection.end.column == 0 && selection.end.row > selection.start.row {
10106            end_row -= 1;
10107        }
10108
10109        // Avoid re-indenting a row that has already been indented by a
10110        // previous selection, but still update this selection's column
10111        // to reflect that indentation.
10112        if delta_for_start_row > 0 {
10113            start_row += 1;
10114            selection.start.column += delta_for_start_row;
10115            if selection.end.row == selection.start.row {
10116                selection.end.column += delta_for_start_row;
10117            }
10118        }
10119
10120        let mut delta_for_end_row = 0;
10121        let has_multiple_rows = start_row + 1 != end_row;
10122        for row in start_row..end_row {
10123            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10124            let indent_delta = match (current_indent.kind, indent_kind) {
10125                (IndentKind::Space, IndentKind::Space) => {
10126                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10127                    IndentSize::spaces(columns_to_next_tab_stop)
10128                }
10129                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10130                (_, IndentKind::Tab) => IndentSize::tab(),
10131            };
10132
10133            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10134                0
10135            } else {
10136                selection.start.column
10137            };
10138            let row_start = Point::new(row, start);
10139            edits.push((
10140                row_start..row_start,
10141                indent_delta.chars().collect::<String>(),
10142            ));
10143
10144            // Update this selection's endpoints to reflect the indentation.
10145            if row == selection.start.row {
10146                selection.start.column += indent_delta.len;
10147            }
10148            if row == selection.end.row {
10149                selection.end.column += indent_delta.len;
10150                delta_for_end_row = indent_delta.len;
10151            }
10152        }
10153
10154        if selection.start.row == selection.end.row {
10155            delta_for_start_row + delta_for_end_row
10156        } else {
10157            delta_for_end_row
10158        }
10159    }
10160
10161    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10162        if self.read_only(cx) {
10163            return;
10164        }
10165        if self.mode.is_single_line() {
10166            cx.propagate();
10167            return;
10168        }
10169
10170        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10171        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10172        let selections = self.selections.all::<Point>(cx);
10173        let mut deletion_ranges = Vec::new();
10174        let mut last_outdent = None;
10175        {
10176            let buffer = self.buffer.read(cx);
10177            let snapshot = buffer.snapshot(cx);
10178            for selection in &selections {
10179                let settings = buffer.language_settings_at(selection.start, cx);
10180                let tab_size = settings.tab_size.get();
10181                let mut rows = selection.spanned_rows(false, &display_map);
10182
10183                // Avoid re-outdenting a row that has already been outdented by a
10184                // previous selection.
10185                if let Some(last_row) = last_outdent
10186                    && last_row == rows.start
10187                {
10188                    rows.start = rows.start.next_row();
10189                }
10190                let has_multiple_rows = rows.len() > 1;
10191                for row in rows.iter_rows() {
10192                    let indent_size = snapshot.indent_size_for_line(row);
10193                    if indent_size.len > 0 {
10194                        let deletion_len = match indent_size.kind {
10195                            IndentKind::Space => {
10196                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10197                                if columns_to_prev_tab_stop == 0 {
10198                                    tab_size
10199                                } else {
10200                                    columns_to_prev_tab_stop
10201                                }
10202                            }
10203                            IndentKind::Tab => 1,
10204                        };
10205                        let start = if has_multiple_rows
10206                            || deletion_len > selection.start.column
10207                            || indent_size.len < selection.start.column
10208                        {
10209                            0
10210                        } else {
10211                            selection.start.column - deletion_len
10212                        };
10213                        deletion_ranges.push(
10214                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10215                        );
10216                        last_outdent = Some(row);
10217                    }
10218                }
10219            }
10220        }
10221
10222        self.transact(window, cx, |this, window, cx| {
10223            this.buffer.update(cx, |buffer, cx| {
10224                let empty_str: Arc<str> = Arc::default();
10225                buffer.edit(
10226                    deletion_ranges
10227                        .into_iter()
10228                        .map(|range| (range, empty_str.clone())),
10229                    None,
10230                    cx,
10231                );
10232            });
10233            let selections = this.selections.all::<usize>(cx);
10234            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10235        });
10236    }
10237
10238    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10239        if self.read_only(cx) {
10240            return;
10241        }
10242        if self.mode.is_single_line() {
10243            cx.propagate();
10244            return;
10245        }
10246
10247        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10248        let selections = self
10249            .selections
10250            .all::<usize>(cx)
10251            .into_iter()
10252            .map(|s| s.range());
10253
10254        self.transact(window, cx, |this, window, cx| {
10255            this.buffer.update(cx, |buffer, cx| {
10256                buffer.autoindent_ranges(selections, cx);
10257            });
10258            let selections = this.selections.all::<usize>(cx);
10259            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10260        });
10261    }
10262
10263    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10264        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10265        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10266        let selections = self.selections.all::<Point>(cx);
10267
10268        let mut new_cursors = Vec::new();
10269        let mut edit_ranges = Vec::new();
10270        let mut selections = selections.iter().peekable();
10271        while let Some(selection) = selections.next() {
10272            let mut rows = selection.spanned_rows(false, &display_map);
10273            let goal_display_column = selection.head().to_display_point(&display_map).column();
10274
10275            // Accumulate contiguous regions of rows that we want to delete.
10276            while let Some(next_selection) = selections.peek() {
10277                let next_rows = next_selection.spanned_rows(false, &display_map);
10278                if next_rows.start <= rows.end {
10279                    rows.end = next_rows.end;
10280                    selections.next().unwrap();
10281                } else {
10282                    break;
10283                }
10284            }
10285
10286            let buffer = &display_map.buffer_snapshot;
10287            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10288            let edit_end;
10289            let cursor_buffer_row;
10290            if buffer.max_point().row >= rows.end.0 {
10291                // If there's a line after the range, delete the \n from the end of the row range
10292                // and position the cursor on the next line.
10293                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10294                cursor_buffer_row = rows.end;
10295            } else {
10296                // If there isn't a line after the range, delete the \n from the line before the
10297                // start of the row range and position the cursor there.
10298                edit_start = edit_start.saturating_sub(1);
10299                edit_end = buffer.len();
10300                cursor_buffer_row = rows.start.previous_row();
10301            }
10302
10303            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10304            *cursor.column_mut() =
10305                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10306
10307            new_cursors.push((
10308                selection.id,
10309                buffer.anchor_after(cursor.to_point(&display_map)),
10310            ));
10311            edit_ranges.push(edit_start..edit_end);
10312        }
10313
10314        self.transact(window, cx, |this, window, cx| {
10315            let buffer = this.buffer.update(cx, |buffer, cx| {
10316                let empty_str: Arc<str> = Arc::default();
10317                buffer.edit(
10318                    edit_ranges
10319                        .into_iter()
10320                        .map(|range| (range, empty_str.clone())),
10321                    None,
10322                    cx,
10323                );
10324                buffer.snapshot(cx)
10325            });
10326            let new_selections = new_cursors
10327                .into_iter()
10328                .map(|(id, cursor)| {
10329                    let cursor = cursor.to_point(&buffer);
10330                    Selection {
10331                        id,
10332                        start: cursor,
10333                        end: cursor,
10334                        reversed: false,
10335                        goal: SelectionGoal::None,
10336                    }
10337                })
10338                .collect();
10339
10340            this.change_selections(Default::default(), window, cx, |s| {
10341                s.select(new_selections);
10342            });
10343        });
10344    }
10345
10346    pub fn join_lines_impl(
10347        &mut self,
10348        insert_whitespace: bool,
10349        window: &mut Window,
10350        cx: &mut Context<Self>,
10351    ) {
10352        if self.read_only(cx) {
10353            return;
10354        }
10355        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10356        for selection in self.selections.all::<Point>(cx) {
10357            let start = MultiBufferRow(selection.start.row);
10358            // Treat single line selections as if they include the next line. Otherwise this action
10359            // would do nothing for single line selections individual cursors.
10360            let end = if selection.start.row == selection.end.row {
10361                MultiBufferRow(selection.start.row + 1)
10362            } else {
10363                MultiBufferRow(selection.end.row)
10364            };
10365
10366            if let Some(last_row_range) = row_ranges.last_mut()
10367                && start <= last_row_range.end
10368            {
10369                last_row_range.end = end;
10370                continue;
10371            }
10372            row_ranges.push(start..end);
10373        }
10374
10375        let snapshot = self.buffer.read(cx).snapshot(cx);
10376        let mut cursor_positions = Vec::new();
10377        for row_range in &row_ranges {
10378            let anchor = snapshot.anchor_before(Point::new(
10379                row_range.end.previous_row().0,
10380                snapshot.line_len(row_range.end.previous_row()),
10381            ));
10382            cursor_positions.push(anchor..anchor);
10383        }
10384
10385        self.transact(window, cx, |this, window, cx| {
10386            for row_range in row_ranges.into_iter().rev() {
10387                for row in row_range.iter_rows().rev() {
10388                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10389                    let next_line_row = row.next_row();
10390                    let indent = snapshot.indent_size_for_line(next_line_row);
10391                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10392
10393                    let replace =
10394                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10395                            " "
10396                        } else {
10397                            ""
10398                        };
10399
10400                    this.buffer.update(cx, |buffer, cx| {
10401                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10402                    });
10403                }
10404            }
10405
10406            this.change_selections(Default::default(), window, cx, |s| {
10407                s.select_anchor_ranges(cursor_positions)
10408            });
10409        });
10410    }
10411
10412    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10413        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10414        self.join_lines_impl(true, window, cx);
10415    }
10416
10417    pub fn sort_lines_case_sensitive(
10418        &mut self,
10419        _: &SortLinesCaseSensitive,
10420        window: &mut Window,
10421        cx: &mut Context<Self>,
10422    ) {
10423        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10424    }
10425
10426    pub fn sort_lines_by_length(
10427        &mut self,
10428        _: &SortLinesByLength,
10429        window: &mut Window,
10430        cx: &mut Context<Self>,
10431    ) {
10432        self.manipulate_immutable_lines(window, cx, |lines| {
10433            lines.sort_by_key(|&line| line.chars().count())
10434        })
10435    }
10436
10437    pub fn sort_lines_case_insensitive(
10438        &mut self,
10439        _: &SortLinesCaseInsensitive,
10440        window: &mut Window,
10441        cx: &mut Context<Self>,
10442    ) {
10443        self.manipulate_immutable_lines(window, cx, |lines| {
10444            lines.sort_by_key(|line| line.to_lowercase())
10445        })
10446    }
10447
10448    pub fn unique_lines_case_insensitive(
10449        &mut self,
10450        _: &UniqueLinesCaseInsensitive,
10451        window: &mut Window,
10452        cx: &mut Context<Self>,
10453    ) {
10454        self.manipulate_immutable_lines(window, cx, |lines| {
10455            let mut seen = HashSet::default();
10456            lines.retain(|line| seen.insert(line.to_lowercase()));
10457        })
10458    }
10459
10460    pub fn unique_lines_case_sensitive(
10461        &mut self,
10462        _: &UniqueLinesCaseSensitive,
10463        window: &mut Window,
10464        cx: &mut Context<Self>,
10465    ) {
10466        self.manipulate_immutable_lines(window, cx, |lines| {
10467            let mut seen = HashSet::default();
10468            lines.retain(|line| seen.insert(*line));
10469        })
10470    }
10471
10472    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10473        let Some(project) = self.project.clone() else {
10474            return;
10475        };
10476        self.reload(project, window, cx)
10477            .detach_and_notify_err(window, cx);
10478    }
10479
10480    pub fn restore_file(
10481        &mut self,
10482        _: &::git::RestoreFile,
10483        window: &mut Window,
10484        cx: &mut Context<Self>,
10485    ) {
10486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10487        let mut buffer_ids = HashSet::default();
10488        let snapshot = self.buffer().read(cx).snapshot(cx);
10489        for selection in self.selections.all::<usize>(cx) {
10490            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10491        }
10492
10493        let buffer = self.buffer().read(cx);
10494        let ranges = buffer_ids
10495            .into_iter()
10496            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10497            .collect::<Vec<_>>();
10498
10499        self.restore_hunks_in_ranges(ranges, window, cx);
10500    }
10501
10502    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10503        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10504        let selections = self
10505            .selections
10506            .all(cx)
10507            .into_iter()
10508            .map(|s| s.range())
10509            .collect();
10510        self.restore_hunks_in_ranges(selections, window, cx);
10511    }
10512
10513    pub fn restore_hunks_in_ranges(
10514        &mut self,
10515        ranges: Vec<Range<Point>>,
10516        window: &mut Window,
10517        cx: &mut Context<Editor>,
10518    ) {
10519        let mut revert_changes = HashMap::default();
10520        let chunk_by = self
10521            .snapshot(window, cx)
10522            .hunks_for_ranges(ranges)
10523            .into_iter()
10524            .chunk_by(|hunk| hunk.buffer_id);
10525        for (buffer_id, hunks) in &chunk_by {
10526            let hunks = hunks.collect::<Vec<_>>();
10527            for hunk in &hunks {
10528                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10529            }
10530            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10531        }
10532        drop(chunk_by);
10533        if !revert_changes.is_empty() {
10534            self.transact(window, cx, |editor, window, cx| {
10535                editor.restore(revert_changes, window, cx);
10536            });
10537        }
10538    }
10539
10540    pub fn open_active_item_in_terminal(
10541        &mut self,
10542        _: &OpenInTerminal,
10543        window: &mut Window,
10544        cx: &mut Context<Self>,
10545    ) {
10546        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10547            let project_path = buffer.read(cx).project_path(cx)?;
10548            let project = self.project()?.read(cx);
10549            let entry = project.entry_for_path(&project_path, cx)?;
10550            let parent = match &entry.canonical_path {
10551                Some(canonical_path) => canonical_path.to_path_buf(),
10552                None => project.absolute_path(&project_path, cx)?,
10553            }
10554            .parent()?
10555            .to_path_buf();
10556            Some(parent)
10557        }) {
10558            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10559        }
10560    }
10561
10562    fn set_breakpoint_context_menu(
10563        &mut self,
10564        display_row: DisplayRow,
10565        position: Option<Anchor>,
10566        clicked_point: gpui::Point<Pixels>,
10567        window: &mut Window,
10568        cx: &mut Context<Self>,
10569    ) {
10570        let source = self
10571            .buffer
10572            .read(cx)
10573            .snapshot(cx)
10574            .anchor_before(Point::new(display_row.0, 0u32));
10575
10576        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10577
10578        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10579            self,
10580            source,
10581            clicked_point,
10582            context_menu,
10583            window,
10584            cx,
10585        );
10586    }
10587
10588    fn add_edit_breakpoint_block(
10589        &mut self,
10590        anchor: Anchor,
10591        breakpoint: &Breakpoint,
10592        edit_action: BreakpointPromptEditAction,
10593        window: &mut Window,
10594        cx: &mut Context<Self>,
10595    ) {
10596        let weak_editor = cx.weak_entity();
10597        let bp_prompt = cx.new(|cx| {
10598            BreakpointPromptEditor::new(
10599                weak_editor,
10600                anchor,
10601                breakpoint.clone(),
10602                edit_action,
10603                window,
10604                cx,
10605            )
10606        });
10607
10608        let height = bp_prompt.update(cx, |this, cx| {
10609            this.prompt
10610                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10611        });
10612        let cloned_prompt = bp_prompt.clone();
10613        let blocks = vec![BlockProperties {
10614            style: BlockStyle::Sticky,
10615            placement: BlockPlacement::Above(anchor),
10616            height: Some(height),
10617            render: Arc::new(move |cx| {
10618                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10619                cloned_prompt.clone().into_any_element()
10620            }),
10621            priority: 0,
10622        }];
10623
10624        let focus_handle = bp_prompt.focus_handle(cx);
10625        window.focus(&focus_handle);
10626
10627        let block_ids = self.insert_blocks(blocks, None, cx);
10628        bp_prompt.update(cx, |prompt, _| {
10629            prompt.add_block_ids(block_ids);
10630        });
10631    }
10632
10633    pub(crate) fn breakpoint_at_row(
10634        &self,
10635        row: u32,
10636        window: &mut Window,
10637        cx: &mut Context<Self>,
10638    ) -> Option<(Anchor, Breakpoint)> {
10639        let snapshot = self.snapshot(window, cx);
10640        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10641
10642        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10643    }
10644
10645    pub(crate) fn breakpoint_at_anchor(
10646        &self,
10647        breakpoint_position: Anchor,
10648        snapshot: &EditorSnapshot,
10649        cx: &mut Context<Self>,
10650    ) -> Option<(Anchor, Breakpoint)> {
10651        let project = self.project.clone()?;
10652
10653        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10654            snapshot
10655                .buffer_snapshot
10656                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10657        })?;
10658
10659        let enclosing_excerpt = breakpoint_position.excerpt_id;
10660        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10661        let buffer_snapshot = buffer.read(cx).snapshot();
10662
10663        let row = buffer_snapshot
10664            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10665            .row;
10666
10667        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10668        let anchor_end = snapshot
10669            .buffer_snapshot
10670            .anchor_after(Point::new(row, line_len));
10671
10672        let bp = self
10673            .breakpoint_store
10674            .as_ref()?
10675            .read_with(cx, |breakpoint_store, cx| {
10676                breakpoint_store
10677                    .breakpoints(
10678                        &buffer,
10679                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10680                        &buffer_snapshot,
10681                        cx,
10682                    )
10683                    .next()
10684                    .and_then(|(bp, _)| {
10685                        let breakpoint_row = buffer_snapshot
10686                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10687                            .row;
10688
10689                        if breakpoint_row == row {
10690                            snapshot
10691                                .buffer_snapshot
10692                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10693                                .map(|position| (position, bp.bp.clone()))
10694                        } else {
10695                            None
10696                        }
10697                    })
10698            });
10699        bp
10700    }
10701
10702    pub fn edit_log_breakpoint(
10703        &mut self,
10704        _: &EditLogBreakpoint,
10705        window: &mut Window,
10706        cx: &mut Context<Self>,
10707    ) {
10708        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10709            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10710                message: None,
10711                state: BreakpointState::Enabled,
10712                condition: None,
10713                hit_condition: None,
10714            });
10715
10716            self.add_edit_breakpoint_block(
10717                anchor,
10718                &breakpoint,
10719                BreakpointPromptEditAction::Log,
10720                window,
10721                cx,
10722            );
10723        }
10724    }
10725
10726    fn breakpoints_at_cursors(
10727        &self,
10728        window: &mut Window,
10729        cx: &mut Context<Self>,
10730    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10731        let snapshot = self.snapshot(window, cx);
10732        let cursors = self
10733            .selections
10734            .disjoint_anchors()
10735            .into_iter()
10736            .map(|selection| {
10737                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10738
10739                let breakpoint_position = self
10740                    .breakpoint_at_row(cursor_position.row, window, cx)
10741                    .map(|bp| bp.0)
10742                    .unwrap_or_else(|| {
10743                        snapshot
10744                            .display_snapshot
10745                            .buffer_snapshot
10746                            .anchor_after(Point::new(cursor_position.row, 0))
10747                    });
10748
10749                let breakpoint = self
10750                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10751                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10752
10753                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10754            })
10755            // 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.
10756            .collect::<HashMap<Anchor, _>>();
10757
10758        cursors.into_iter().collect()
10759    }
10760
10761    pub fn enable_breakpoint(
10762        &mut self,
10763        _: &crate::actions::EnableBreakpoint,
10764        window: &mut Window,
10765        cx: &mut Context<Self>,
10766    ) {
10767        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10768            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10769                continue;
10770            };
10771            self.edit_breakpoint_at_anchor(
10772                anchor,
10773                breakpoint,
10774                BreakpointEditAction::InvertState,
10775                cx,
10776            );
10777        }
10778    }
10779
10780    pub fn disable_breakpoint(
10781        &mut self,
10782        _: &crate::actions::DisableBreakpoint,
10783        window: &mut Window,
10784        cx: &mut Context<Self>,
10785    ) {
10786        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10787            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10788                continue;
10789            };
10790            self.edit_breakpoint_at_anchor(
10791                anchor,
10792                breakpoint,
10793                BreakpointEditAction::InvertState,
10794                cx,
10795            );
10796        }
10797    }
10798
10799    pub fn toggle_breakpoint(
10800        &mut self,
10801        _: &crate::actions::ToggleBreakpoint,
10802        window: &mut Window,
10803        cx: &mut Context<Self>,
10804    ) {
10805        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10806            if let Some(breakpoint) = breakpoint {
10807                self.edit_breakpoint_at_anchor(
10808                    anchor,
10809                    breakpoint,
10810                    BreakpointEditAction::Toggle,
10811                    cx,
10812                );
10813            } else {
10814                self.edit_breakpoint_at_anchor(
10815                    anchor,
10816                    Breakpoint::new_standard(),
10817                    BreakpointEditAction::Toggle,
10818                    cx,
10819                );
10820            }
10821        }
10822    }
10823
10824    pub fn edit_breakpoint_at_anchor(
10825        &mut self,
10826        breakpoint_position: Anchor,
10827        breakpoint: Breakpoint,
10828        edit_action: BreakpointEditAction,
10829        cx: &mut Context<Self>,
10830    ) {
10831        let Some(breakpoint_store) = &self.breakpoint_store else {
10832            return;
10833        };
10834
10835        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10836            if breakpoint_position == Anchor::min() {
10837                self.buffer()
10838                    .read(cx)
10839                    .excerpt_buffer_ids()
10840                    .into_iter()
10841                    .next()
10842            } else {
10843                None
10844            }
10845        }) else {
10846            return;
10847        };
10848
10849        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10850            return;
10851        };
10852
10853        breakpoint_store.update(cx, |breakpoint_store, cx| {
10854            breakpoint_store.toggle_breakpoint(
10855                buffer,
10856                BreakpointWithPosition {
10857                    position: breakpoint_position.text_anchor,
10858                    bp: breakpoint,
10859                },
10860                edit_action,
10861                cx,
10862            );
10863        });
10864
10865        cx.notify();
10866    }
10867
10868    #[cfg(any(test, feature = "test-support"))]
10869    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10870        self.breakpoint_store.clone()
10871    }
10872
10873    pub fn prepare_restore_change(
10874        &self,
10875        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10876        hunk: &MultiBufferDiffHunk,
10877        cx: &mut App,
10878    ) -> Option<()> {
10879        if hunk.is_created_file() {
10880            return None;
10881        }
10882        let buffer = self.buffer.read(cx);
10883        let diff = buffer.diff_for(hunk.buffer_id)?;
10884        let buffer = buffer.buffer(hunk.buffer_id)?;
10885        let buffer = buffer.read(cx);
10886        let original_text = diff
10887            .read(cx)
10888            .base_text()
10889            .as_rope()
10890            .slice(hunk.diff_base_byte_range.clone());
10891        let buffer_snapshot = buffer.snapshot();
10892        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10893        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10894            probe
10895                .0
10896                .start
10897                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10898                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10899        }) {
10900            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10901            Some(())
10902        } else {
10903            None
10904        }
10905    }
10906
10907    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10908        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10909    }
10910
10911    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10912        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10913    }
10914
10915    fn manipulate_lines<M>(
10916        &mut self,
10917        window: &mut Window,
10918        cx: &mut Context<Self>,
10919        mut manipulate: M,
10920    ) where
10921        M: FnMut(&str) -> LineManipulationResult,
10922    {
10923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10924
10925        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10926        let buffer = self.buffer.read(cx).snapshot(cx);
10927
10928        let mut edits = Vec::new();
10929
10930        let selections = self.selections.all::<Point>(cx);
10931        let mut selections = selections.iter().peekable();
10932        let mut contiguous_row_selections = Vec::new();
10933        let mut new_selections = Vec::new();
10934        let mut added_lines = 0;
10935        let mut removed_lines = 0;
10936
10937        while let Some(selection) = selections.next() {
10938            let (start_row, end_row) = consume_contiguous_rows(
10939                &mut contiguous_row_selections,
10940                selection,
10941                &display_map,
10942                &mut selections,
10943            );
10944
10945            let start_point = Point::new(start_row.0, 0);
10946            let end_point = Point::new(
10947                end_row.previous_row().0,
10948                buffer.line_len(end_row.previous_row()),
10949            );
10950            let text = buffer
10951                .text_for_range(start_point..end_point)
10952                .collect::<String>();
10953
10954            let LineManipulationResult {
10955                new_text,
10956                line_count_before,
10957                line_count_after,
10958            } = manipulate(&text);
10959
10960            edits.push((start_point..end_point, new_text));
10961
10962            // Selections must change based on added and removed line count
10963            let start_row =
10964                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10965            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10966            new_selections.push(Selection {
10967                id: selection.id,
10968                start: start_row,
10969                end: end_row,
10970                goal: SelectionGoal::None,
10971                reversed: selection.reversed,
10972            });
10973
10974            if line_count_after > line_count_before {
10975                added_lines += line_count_after - line_count_before;
10976            } else if line_count_before > line_count_after {
10977                removed_lines += line_count_before - line_count_after;
10978            }
10979        }
10980
10981        self.transact(window, cx, |this, window, cx| {
10982            let buffer = this.buffer.update(cx, |buffer, cx| {
10983                buffer.edit(edits, None, cx);
10984                buffer.snapshot(cx)
10985            });
10986
10987            // Recalculate offsets on newly edited buffer
10988            let new_selections = new_selections
10989                .iter()
10990                .map(|s| {
10991                    let start_point = Point::new(s.start.0, 0);
10992                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10993                    Selection {
10994                        id: s.id,
10995                        start: buffer.point_to_offset(start_point),
10996                        end: buffer.point_to_offset(end_point),
10997                        goal: s.goal,
10998                        reversed: s.reversed,
10999                    }
11000                })
11001                .collect();
11002
11003            this.change_selections(Default::default(), window, cx, |s| {
11004                s.select(new_selections);
11005            });
11006
11007            this.request_autoscroll(Autoscroll::fit(), cx);
11008        });
11009    }
11010
11011    fn manipulate_immutable_lines<Fn>(
11012        &mut self,
11013        window: &mut Window,
11014        cx: &mut Context<Self>,
11015        mut callback: Fn,
11016    ) where
11017        Fn: FnMut(&mut Vec<&str>),
11018    {
11019        self.manipulate_lines(window, cx, |text| {
11020            let mut lines: Vec<&str> = text.split('\n').collect();
11021            let line_count_before = lines.len();
11022
11023            callback(&mut lines);
11024
11025            LineManipulationResult {
11026                new_text: lines.join("\n"),
11027                line_count_before,
11028                line_count_after: lines.len(),
11029            }
11030        });
11031    }
11032
11033    fn manipulate_mutable_lines<Fn>(
11034        &mut self,
11035        window: &mut Window,
11036        cx: &mut Context<Self>,
11037        mut callback: Fn,
11038    ) where
11039        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11040    {
11041        self.manipulate_lines(window, cx, |text| {
11042            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11043            let line_count_before = lines.len();
11044
11045            callback(&mut lines);
11046
11047            LineManipulationResult {
11048                new_text: lines.join("\n"),
11049                line_count_before,
11050                line_count_after: lines.len(),
11051            }
11052        });
11053    }
11054
11055    pub fn convert_indentation_to_spaces(
11056        &mut self,
11057        _: &ConvertIndentationToSpaces,
11058        window: &mut Window,
11059        cx: &mut Context<Self>,
11060    ) {
11061        let settings = self.buffer.read(cx).language_settings(cx);
11062        let tab_size = settings.tab_size.get() as usize;
11063
11064        self.manipulate_mutable_lines(window, cx, |lines| {
11065            // Allocates a reasonably sized scratch buffer once for the whole loop
11066            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11067            // Avoids recomputing spaces that could be inserted many times
11068            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11069                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11070                .collect();
11071
11072            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11073                let mut chars = line.as_ref().chars();
11074                let mut col = 0;
11075                let mut changed = false;
11076
11077                while let Some(ch) = chars.next() {
11078                    match ch {
11079                        ' ' => {
11080                            reindented_line.push(' ');
11081                            col += 1;
11082                        }
11083                        '\t' => {
11084                            // \t are converted to spaces depending on the current column
11085                            let spaces_len = tab_size - (col % tab_size);
11086                            reindented_line.extend(&space_cache[spaces_len - 1]);
11087                            col += spaces_len;
11088                            changed = true;
11089                        }
11090                        _ => {
11091                            // If we dont append before break, the character is consumed
11092                            reindented_line.push(ch);
11093                            break;
11094                        }
11095                    }
11096                }
11097
11098                if !changed {
11099                    reindented_line.clear();
11100                    continue;
11101                }
11102                // Append the rest of the line and replace old reference with new one
11103                reindented_line.extend(chars);
11104                *line = Cow::Owned(reindented_line.clone());
11105                reindented_line.clear();
11106            }
11107        });
11108    }
11109
11110    pub fn convert_indentation_to_tabs(
11111        &mut self,
11112        _: &ConvertIndentationToTabs,
11113        window: &mut Window,
11114        cx: &mut Context<Self>,
11115    ) {
11116        let settings = self.buffer.read(cx).language_settings(cx);
11117        let tab_size = settings.tab_size.get() as usize;
11118
11119        self.manipulate_mutable_lines(window, cx, |lines| {
11120            // Allocates a reasonably sized buffer once for the whole loop
11121            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11122            // Avoids recomputing spaces that could be inserted many times
11123            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11124                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11125                .collect();
11126
11127            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11128                let mut chars = line.chars();
11129                let mut spaces_count = 0;
11130                let mut first_non_indent_char = None;
11131                let mut changed = false;
11132
11133                while let Some(ch) = chars.next() {
11134                    match ch {
11135                        ' ' => {
11136                            // Keep track of spaces. Append \t when we reach tab_size
11137                            spaces_count += 1;
11138                            changed = true;
11139                            if spaces_count == tab_size {
11140                                reindented_line.push('\t');
11141                                spaces_count = 0;
11142                            }
11143                        }
11144                        '\t' => {
11145                            reindented_line.push('\t');
11146                            spaces_count = 0;
11147                        }
11148                        _ => {
11149                            // Dont append it yet, we might have remaining spaces
11150                            first_non_indent_char = Some(ch);
11151                            break;
11152                        }
11153                    }
11154                }
11155
11156                if !changed {
11157                    reindented_line.clear();
11158                    continue;
11159                }
11160                // Remaining spaces that didn't make a full tab stop
11161                if spaces_count > 0 {
11162                    reindented_line.extend(&space_cache[spaces_count - 1]);
11163                }
11164                // If we consume an extra character that was not indentation, add it back
11165                if let Some(extra_char) = first_non_indent_char {
11166                    reindented_line.push(extra_char);
11167                }
11168                // Append the rest of the line and replace old reference with new one
11169                reindented_line.extend(chars);
11170                *line = Cow::Owned(reindented_line.clone());
11171                reindented_line.clear();
11172            }
11173        });
11174    }
11175
11176    pub fn convert_to_upper_case(
11177        &mut self,
11178        _: &ConvertToUpperCase,
11179        window: &mut Window,
11180        cx: &mut Context<Self>,
11181    ) {
11182        self.manipulate_text(window, cx, |text| text.to_uppercase())
11183    }
11184
11185    pub fn convert_to_lower_case(
11186        &mut self,
11187        _: &ConvertToLowerCase,
11188        window: &mut Window,
11189        cx: &mut Context<Self>,
11190    ) {
11191        self.manipulate_text(window, cx, |text| text.to_lowercase())
11192    }
11193
11194    pub fn convert_to_title_case(
11195        &mut self,
11196        _: &ConvertToTitleCase,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        self.manipulate_text(window, cx, |text| {
11201            text.split('\n')
11202                .map(|line| line.to_case(Case::Title))
11203                .join("\n")
11204        })
11205    }
11206
11207    pub fn convert_to_snake_case(
11208        &mut self,
11209        _: &ConvertToSnakeCase,
11210        window: &mut Window,
11211        cx: &mut Context<Self>,
11212    ) {
11213        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11214    }
11215
11216    pub fn convert_to_kebab_case(
11217        &mut self,
11218        _: &ConvertToKebabCase,
11219        window: &mut Window,
11220        cx: &mut Context<Self>,
11221    ) {
11222        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11223    }
11224
11225    pub fn convert_to_upper_camel_case(
11226        &mut self,
11227        _: &ConvertToUpperCamelCase,
11228        window: &mut Window,
11229        cx: &mut Context<Self>,
11230    ) {
11231        self.manipulate_text(window, cx, |text| {
11232            text.split('\n')
11233                .map(|line| line.to_case(Case::UpperCamel))
11234                .join("\n")
11235        })
11236    }
11237
11238    pub fn convert_to_lower_camel_case(
11239        &mut self,
11240        _: &ConvertToLowerCamelCase,
11241        window: &mut Window,
11242        cx: &mut Context<Self>,
11243    ) {
11244        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11245    }
11246
11247    pub fn convert_to_opposite_case(
11248        &mut self,
11249        _: &ConvertToOppositeCase,
11250        window: &mut Window,
11251        cx: &mut Context<Self>,
11252    ) {
11253        self.manipulate_text(window, cx, |text| {
11254            text.chars()
11255                .fold(String::with_capacity(text.len()), |mut t, c| {
11256                    if c.is_uppercase() {
11257                        t.extend(c.to_lowercase());
11258                    } else {
11259                        t.extend(c.to_uppercase());
11260                    }
11261                    t
11262                })
11263        })
11264    }
11265
11266    pub fn convert_to_sentence_case(
11267        &mut self,
11268        _: &ConvertToSentenceCase,
11269        window: &mut Window,
11270        cx: &mut Context<Self>,
11271    ) {
11272        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11273    }
11274
11275    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11276        self.manipulate_text(window, cx, |text| {
11277            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11278            if has_upper_case_characters {
11279                text.to_lowercase()
11280            } else {
11281                text.to_uppercase()
11282            }
11283        })
11284    }
11285
11286    pub fn convert_to_rot13(
11287        &mut self,
11288        _: &ConvertToRot13,
11289        window: &mut Window,
11290        cx: &mut Context<Self>,
11291    ) {
11292        self.manipulate_text(window, cx, |text| {
11293            text.chars()
11294                .map(|c| match c {
11295                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11296                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11297                    _ => c,
11298                })
11299                .collect()
11300        })
11301    }
11302
11303    pub fn convert_to_rot47(
11304        &mut self,
11305        _: &ConvertToRot47,
11306        window: &mut Window,
11307        cx: &mut Context<Self>,
11308    ) {
11309        self.manipulate_text(window, cx, |text| {
11310            text.chars()
11311                .map(|c| {
11312                    let code_point = c as u32;
11313                    if code_point >= 33 && code_point <= 126 {
11314                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11315                    }
11316                    c
11317                })
11318                .collect()
11319        })
11320    }
11321
11322    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11323    where
11324        Fn: FnMut(&str) -> String,
11325    {
11326        let buffer = self.buffer.read(cx).snapshot(cx);
11327
11328        let mut new_selections = Vec::new();
11329        let mut edits = Vec::new();
11330        let mut selection_adjustment = 0i32;
11331
11332        for selection in self.selections.all::<usize>(cx) {
11333            let selection_is_empty = selection.is_empty();
11334
11335            let (start, end) = if selection_is_empty {
11336                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11337                (word_range.start, word_range.end)
11338            } else {
11339                (selection.start, selection.end)
11340            };
11341
11342            let text = buffer.text_for_range(start..end).collect::<String>();
11343            let old_length = text.len() as i32;
11344            let text = callback(&text);
11345
11346            new_selections.push(Selection {
11347                start: (start as i32 - selection_adjustment) as usize,
11348                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11349                goal: SelectionGoal::None,
11350                ..selection
11351            });
11352
11353            selection_adjustment += old_length - text.len() as i32;
11354
11355            edits.push((start..end, text));
11356        }
11357
11358        self.transact(window, cx, |this, window, cx| {
11359            this.buffer.update(cx, |buffer, cx| {
11360                buffer.edit(edits, None, cx);
11361            });
11362
11363            this.change_selections(Default::default(), window, cx, |s| {
11364                s.select(new_selections);
11365            });
11366
11367            this.request_autoscroll(Autoscroll::fit(), cx);
11368        });
11369    }
11370
11371    pub fn move_selection_on_drop(
11372        &mut self,
11373        selection: &Selection<Anchor>,
11374        target: DisplayPoint,
11375        is_cut: bool,
11376        window: &mut Window,
11377        cx: &mut Context<Self>,
11378    ) {
11379        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11380        let buffer = &display_map.buffer_snapshot;
11381        let mut edits = Vec::new();
11382        let insert_point = display_map
11383            .clip_point(target, Bias::Left)
11384            .to_point(&display_map);
11385        let text = buffer
11386            .text_for_range(selection.start..selection.end)
11387            .collect::<String>();
11388        if is_cut {
11389            edits.push(((selection.start..selection.end), String::new()));
11390        }
11391        let insert_anchor = buffer.anchor_before(insert_point);
11392        edits.push(((insert_anchor..insert_anchor), text));
11393        let last_edit_start = insert_anchor.bias_left(buffer);
11394        let last_edit_end = insert_anchor.bias_right(buffer);
11395        self.transact(window, cx, |this, window, cx| {
11396            this.buffer.update(cx, |buffer, cx| {
11397                buffer.edit(edits, None, cx);
11398            });
11399            this.change_selections(Default::default(), window, cx, |s| {
11400                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11401            });
11402        });
11403    }
11404
11405    pub fn clear_selection_drag_state(&mut self) {
11406        self.selection_drag_state = SelectionDragState::None;
11407    }
11408
11409    pub fn duplicate(
11410        &mut self,
11411        upwards: bool,
11412        whole_lines: bool,
11413        window: &mut Window,
11414        cx: &mut Context<Self>,
11415    ) {
11416        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11417
11418        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11419        let buffer = &display_map.buffer_snapshot;
11420        let selections = self.selections.all::<Point>(cx);
11421
11422        let mut edits = Vec::new();
11423        let mut selections_iter = selections.iter().peekable();
11424        while let Some(selection) = selections_iter.next() {
11425            let mut rows = selection.spanned_rows(false, &display_map);
11426            // duplicate line-wise
11427            if whole_lines || selection.start == selection.end {
11428                // Avoid duplicating the same lines twice.
11429                while let Some(next_selection) = selections_iter.peek() {
11430                    let next_rows = next_selection.spanned_rows(false, &display_map);
11431                    if next_rows.start < rows.end {
11432                        rows.end = next_rows.end;
11433                        selections_iter.next().unwrap();
11434                    } else {
11435                        break;
11436                    }
11437                }
11438
11439                // Copy the text from the selected row region and splice it either at the start
11440                // or end of the region.
11441                let start = Point::new(rows.start.0, 0);
11442                let end = Point::new(
11443                    rows.end.previous_row().0,
11444                    buffer.line_len(rows.end.previous_row()),
11445                );
11446                let text = buffer
11447                    .text_for_range(start..end)
11448                    .chain(Some("\n"))
11449                    .collect::<String>();
11450                let insert_location = if upwards {
11451                    Point::new(rows.end.0, 0)
11452                } else {
11453                    start
11454                };
11455                edits.push((insert_location..insert_location, text));
11456            } else {
11457                // duplicate character-wise
11458                let start = selection.start;
11459                let end = selection.end;
11460                let text = buffer.text_for_range(start..end).collect::<String>();
11461                edits.push((selection.end..selection.end, text));
11462            }
11463        }
11464
11465        self.transact(window, cx, |this, _, cx| {
11466            this.buffer.update(cx, |buffer, cx| {
11467                buffer.edit(edits, None, cx);
11468            });
11469
11470            this.request_autoscroll(Autoscroll::fit(), cx);
11471        });
11472    }
11473
11474    pub fn duplicate_line_up(
11475        &mut self,
11476        _: &DuplicateLineUp,
11477        window: &mut Window,
11478        cx: &mut Context<Self>,
11479    ) {
11480        self.duplicate(true, true, window, cx);
11481    }
11482
11483    pub fn duplicate_line_down(
11484        &mut self,
11485        _: &DuplicateLineDown,
11486        window: &mut Window,
11487        cx: &mut Context<Self>,
11488    ) {
11489        self.duplicate(false, true, window, cx);
11490    }
11491
11492    pub fn duplicate_selection(
11493        &mut self,
11494        _: &DuplicateSelection,
11495        window: &mut Window,
11496        cx: &mut Context<Self>,
11497    ) {
11498        self.duplicate(false, false, window, cx);
11499    }
11500
11501    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11502        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11503        if self.mode.is_single_line() {
11504            cx.propagate();
11505            return;
11506        }
11507
11508        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11509        let buffer = self.buffer.read(cx).snapshot(cx);
11510
11511        let mut edits = Vec::new();
11512        let mut unfold_ranges = Vec::new();
11513        let mut refold_creases = Vec::new();
11514
11515        let selections = self.selections.all::<Point>(cx);
11516        let mut selections = selections.iter().peekable();
11517        let mut contiguous_row_selections = Vec::new();
11518        let mut new_selections = Vec::new();
11519
11520        while let Some(selection) = selections.next() {
11521            // Find all the selections that span a contiguous row range
11522            let (start_row, end_row) = consume_contiguous_rows(
11523                &mut contiguous_row_selections,
11524                selection,
11525                &display_map,
11526                &mut selections,
11527            );
11528
11529            // Move the text spanned by the row range to be before the line preceding the row range
11530            if start_row.0 > 0 {
11531                let range_to_move = Point::new(
11532                    start_row.previous_row().0,
11533                    buffer.line_len(start_row.previous_row()),
11534                )
11535                    ..Point::new(
11536                        end_row.previous_row().0,
11537                        buffer.line_len(end_row.previous_row()),
11538                    );
11539                let insertion_point = display_map
11540                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11541                    .0;
11542
11543                // Don't move lines across excerpts
11544                if buffer
11545                    .excerpt_containing(insertion_point..range_to_move.end)
11546                    .is_some()
11547                {
11548                    let text = buffer
11549                        .text_for_range(range_to_move.clone())
11550                        .flat_map(|s| s.chars())
11551                        .skip(1)
11552                        .chain(['\n'])
11553                        .collect::<String>();
11554
11555                    edits.push((
11556                        buffer.anchor_after(range_to_move.start)
11557                            ..buffer.anchor_before(range_to_move.end),
11558                        String::new(),
11559                    ));
11560                    let insertion_anchor = buffer.anchor_after(insertion_point);
11561                    edits.push((insertion_anchor..insertion_anchor, text));
11562
11563                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11564
11565                    // Move selections up
11566                    new_selections.extend(contiguous_row_selections.drain(..).map(
11567                        |mut selection| {
11568                            selection.start.row -= row_delta;
11569                            selection.end.row -= row_delta;
11570                            selection
11571                        },
11572                    ));
11573
11574                    // Move folds up
11575                    unfold_ranges.push(range_to_move.clone());
11576                    for fold in display_map.folds_in_range(
11577                        buffer.anchor_before(range_to_move.start)
11578                            ..buffer.anchor_after(range_to_move.end),
11579                    ) {
11580                        let mut start = fold.range.start.to_point(&buffer);
11581                        let mut end = fold.range.end.to_point(&buffer);
11582                        start.row -= row_delta;
11583                        end.row -= row_delta;
11584                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11585                    }
11586                }
11587            }
11588
11589            // If we didn't move line(s), preserve the existing selections
11590            new_selections.append(&mut contiguous_row_selections);
11591        }
11592
11593        self.transact(window, cx, |this, window, cx| {
11594            this.unfold_ranges(&unfold_ranges, true, true, cx);
11595            this.buffer.update(cx, |buffer, cx| {
11596                for (range, text) in edits {
11597                    buffer.edit([(range, text)], None, cx);
11598                }
11599            });
11600            this.fold_creases(refold_creases, true, window, cx);
11601            this.change_selections(Default::default(), window, cx, |s| {
11602                s.select(new_selections);
11603            })
11604        });
11605    }
11606
11607    pub fn move_line_down(
11608        &mut self,
11609        _: &MoveLineDown,
11610        window: &mut Window,
11611        cx: &mut Context<Self>,
11612    ) {
11613        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11614        if self.mode.is_single_line() {
11615            cx.propagate();
11616            return;
11617        }
11618
11619        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11620        let buffer = self.buffer.read(cx).snapshot(cx);
11621
11622        let mut edits = Vec::new();
11623        let mut unfold_ranges = Vec::new();
11624        let mut refold_creases = Vec::new();
11625
11626        let selections = self.selections.all::<Point>(cx);
11627        let mut selections = selections.iter().peekable();
11628        let mut contiguous_row_selections = Vec::new();
11629        let mut new_selections = Vec::new();
11630
11631        while let Some(selection) = selections.next() {
11632            // Find all the selections that span a contiguous row range
11633            let (start_row, end_row) = consume_contiguous_rows(
11634                &mut contiguous_row_selections,
11635                selection,
11636                &display_map,
11637                &mut selections,
11638            );
11639
11640            // Move the text spanned by the row range to be after the last line of the row range
11641            if end_row.0 <= buffer.max_point().row {
11642                let range_to_move =
11643                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11644                let insertion_point = display_map
11645                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11646                    .0;
11647
11648                // Don't move lines across excerpt boundaries
11649                if buffer
11650                    .excerpt_containing(range_to_move.start..insertion_point)
11651                    .is_some()
11652                {
11653                    let mut text = String::from("\n");
11654                    text.extend(buffer.text_for_range(range_to_move.clone()));
11655                    text.pop(); // Drop trailing newline
11656                    edits.push((
11657                        buffer.anchor_after(range_to_move.start)
11658                            ..buffer.anchor_before(range_to_move.end),
11659                        String::new(),
11660                    ));
11661                    let insertion_anchor = buffer.anchor_after(insertion_point);
11662                    edits.push((insertion_anchor..insertion_anchor, text));
11663
11664                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11665
11666                    // Move selections down
11667                    new_selections.extend(contiguous_row_selections.drain(..).map(
11668                        |mut selection| {
11669                            selection.start.row += row_delta;
11670                            selection.end.row += row_delta;
11671                            selection
11672                        },
11673                    ));
11674
11675                    // Move folds down
11676                    unfold_ranges.push(range_to_move.clone());
11677                    for fold in display_map.folds_in_range(
11678                        buffer.anchor_before(range_to_move.start)
11679                            ..buffer.anchor_after(range_to_move.end),
11680                    ) {
11681                        let mut start = fold.range.start.to_point(&buffer);
11682                        let mut end = fold.range.end.to_point(&buffer);
11683                        start.row += row_delta;
11684                        end.row += row_delta;
11685                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11686                    }
11687                }
11688            }
11689
11690            // If we didn't move line(s), preserve the existing selections
11691            new_selections.append(&mut contiguous_row_selections);
11692        }
11693
11694        self.transact(window, cx, |this, window, cx| {
11695            this.unfold_ranges(&unfold_ranges, true, true, cx);
11696            this.buffer.update(cx, |buffer, cx| {
11697                for (range, text) in edits {
11698                    buffer.edit([(range, text)], None, cx);
11699                }
11700            });
11701            this.fold_creases(refold_creases, true, window, cx);
11702            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11703        });
11704    }
11705
11706    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11707        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11708        let text_layout_details = &self.text_layout_details(window);
11709        self.transact(window, cx, |this, window, cx| {
11710            let edits = this.change_selections(Default::default(), window, cx, |s| {
11711                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11712                s.move_with(|display_map, selection| {
11713                    if !selection.is_empty() {
11714                        return;
11715                    }
11716
11717                    let mut head = selection.head();
11718                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11719                    if head.column() == display_map.line_len(head.row()) {
11720                        transpose_offset = display_map
11721                            .buffer_snapshot
11722                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11723                    }
11724
11725                    if transpose_offset == 0 {
11726                        return;
11727                    }
11728
11729                    *head.column_mut() += 1;
11730                    head = display_map.clip_point(head, Bias::Right);
11731                    let goal = SelectionGoal::HorizontalPosition(
11732                        display_map
11733                            .x_for_display_point(head, text_layout_details)
11734                            .into(),
11735                    );
11736                    selection.collapse_to(head, goal);
11737
11738                    let transpose_start = display_map
11739                        .buffer_snapshot
11740                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11741                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11742                        let transpose_end = display_map
11743                            .buffer_snapshot
11744                            .clip_offset(transpose_offset + 1, Bias::Right);
11745                        if let Some(ch) =
11746                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11747                        {
11748                            edits.push((transpose_start..transpose_offset, String::new()));
11749                            edits.push((transpose_end..transpose_end, ch.to_string()));
11750                        }
11751                    }
11752                });
11753                edits
11754            });
11755            this.buffer
11756                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11757            let selections = this.selections.all::<usize>(cx);
11758            this.change_selections(Default::default(), window, cx, |s| {
11759                s.select(selections);
11760            });
11761        });
11762    }
11763
11764    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11765        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11766        if self.mode.is_single_line() {
11767            cx.propagate();
11768            return;
11769        }
11770
11771        self.rewrap_impl(RewrapOptions::default(), cx)
11772    }
11773
11774    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11775        let buffer = self.buffer.read(cx).snapshot(cx);
11776        let selections = self.selections.all::<Point>(cx);
11777
11778        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11779        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11780            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11781                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11782                .peekable();
11783
11784            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11785                row
11786            } else {
11787                return Vec::new();
11788            };
11789
11790            let language_settings = buffer.language_settings_at(selection.head(), cx);
11791            let language_scope = buffer.language_scope_at(selection.head());
11792
11793            let indent_and_prefix_for_row =
11794                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11795                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11796                    let (comment_prefix, rewrap_prefix) =
11797                        if let Some(language_scope) = &language_scope {
11798                            let indent_end = Point::new(row, indent.len);
11799                            let comment_prefix = language_scope
11800                                .line_comment_prefixes()
11801                                .iter()
11802                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11803                                .map(|prefix| prefix.to_string());
11804                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11805                            let line_text_after_indent = buffer
11806                                .text_for_range(indent_end..line_end)
11807                                .collect::<String>();
11808                            let rewrap_prefix = language_scope
11809                                .rewrap_prefixes()
11810                                .iter()
11811                                .find_map(|prefix_regex| {
11812                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11813                                        if mat.start() == 0 {
11814                                            Some(mat.as_str().to_string())
11815                                        } else {
11816                                            None
11817                                        }
11818                                    })
11819                                })
11820                                .flatten();
11821                            (comment_prefix, rewrap_prefix)
11822                        } else {
11823                            (None, None)
11824                        };
11825                    (indent, comment_prefix, rewrap_prefix)
11826                };
11827
11828            let mut ranges = Vec::new();
11829            let from_empty_selection = selection.is_empty();
11830
11831            let mut current_range_start = first_row;
11832            let mut prev_row = first_row;
11833            let (
11834                mut current_range_indent,
11835                mut current_range_comment_prefix,
11836                mut current_range_rewrap_prefix,
11837            ) = indent_and_prefix_for_row(first_row);
11838
11839            for row in non_blank_rows_iter.skip(1) {
11840                let has_paragraph_break = row > prev_row + 1;
11841
11842                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11843                    indent_and_prefix_for_row(row);
11844
11845                let has_indent_change = row_indent != current_range_indent;
11846                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11847
11848                let has_boundary_change = has_comment_change
11849                    || row_rewrap_prefix.is_some()
11850                    || (has_indent_change && current_range_comment_prefix.is_some());
11851
11852                if has_paragraph_break || has_boundary_change {
11853                    ranges.push((
11854                        language_settings.clone(),
11855                        Point::new(current_range_start, 0)
11856                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11857                        current_range_indent,
11858                        current_range_comment_prefix.clone(),
11859                        current_range_rewrap_prefix.clone(),
11860                        from_empty_selection,
11861                    ));
11862                    current_range_start = row;
11863                    current_range_indent = row_indent;
11864                    current_range_comment_prefix = row_comment_prefix;
11865                    current_range_rewrap_prefix = row_rewrap_prefix;
11866                }
11867                prev_row = row;
11868            }
11869
11870            ranges.push((
11871                language_settings.clone(),
11872                Point::new(current_range_start, 0)
11873                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11874                current_range_indent,
11875                current_range_comment_prefix,
11876                current_range_rewrap_prefix,
11877                from_empty_selection,
11878            ));
11879
11880            ranges
11881        });
11882
11883        let mut edits = Vec::new();
11884        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11885
11886        for (
11887            language_settings,
11888            wrap_range,
11889            indent_size,
11890            comment_prefix,
11891            rewrap_prefix,
11892            from_empty_selection,
11893        ) in wrap_ranges
11894        {
11895            let mut start_row = wrap_range.start.row;
11896            let mut end_row = wrap_range.end.row;
11897
11898            // Skip selections that overlap with a range that has already been rewrapped.
11899            let selection_range = start_row..end_row;
11900            if rewrapped_row_ranges
11901                .iter()
11902                .any(|range| range.overlaps(&selection_range))
11903            {
11904                continue;
11905            }
11906
11907            let tab_size = language_settings.tab_size;
11908
11909            let indent_prefix = indent_size.chars().collect::<String>();
11910            let mut line_prefix = indent_prefix.clone();
11911            let mut inside_comment = false;
11912            if let Some(prefix) = &comment_prefix {
11913                line_prefix.push_str(prefix);
11914                inside_comment = true;
11915            }
11916            if let Some(prefix) = &rewrap_prefix {
11917                line_prefix.push_str(prefix);
11918            }
11919
11920            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11921                RewrapBehavior::InComments => inside_comment,
11922                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11923                RewrapBehavior::Anywhere => true,
11924            };
11925
11926            let should_rewrap = options.override_language_settings
11927                || allow_rewrap_based_on_language
11928                || self.hard_wrap.is_some();
11929            if !should_rewrap {
11930                continue;
11931            }
11932
11933            if from_empty_selection {
11934                'expand_upwards: while start_row > 0 {
11935                    let prev_row = start_row - 1;
11936                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11937                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11938                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11939                    {
11940                        start_row = prev_row;
11941                    } else {
11942                        break 'expand_upwards;
11943                    }
11944                }
11945
11946                'expand_downwards: while end_row < buffer.max_point().row {
11947                    let next_row = end_row + 1;
11948                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11949                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11950                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11951                    {
11952                        end_row = next_row;
11953                    } else {
11954                        break 'expand_downwards;
11955                    }
11956                }
11957            }
11958
11959            let start = Point::new(start_row, 0);
11960            let start_offset = start.to_offset(&buffer);
11961            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11962            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11963            let Some(lines_without_prefixes) = selection_text
11964                .lines()
11965                .enumerate()
11966                .map(|(ix, line)| {
11967                    let line_trimmed = line.trim_start();
11968                    if rewrap_prefix.is_some() && ix > 0 {
11969                        Ok(line_trimmed)
11970                    } else {
11971                        line_trimmed
11972                            .strip_prefix(&line_prefix.trim_start())
11973                            .with_context(|| {
11974                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11975                            })
11976                    }
11977                })
11978                .collect::<Result<Vec<_>, _>>()
11979                .log_err()
11980            else {
11981                continue;
11982            };
11983
11984            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11985                buffer
11986                    .language_settings_at(Point::new(start_row, 0), cx)
11987                    .preferred_line_length as usize
11988            });
11989
11990            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11991                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11992            } else {
11993                line_prefix.clone()
11994            };
11995
11996            let wrapped_text = wrap_with_prefix(
11997                line_prefix,
11998                subsequent_lines_prefix,
11999                lines_without_prefixes.join("\n"),
12000                wrap_column,
12001                tab_size,
12002                options.preserve_existing_whitespace,
12003            );
12004
12005            // TODO: should always use char-based diff while still supporting cursor behavior that
12006            // matches vim.
12007            let mut diff_options = DiffOptions::default();
12008            if options.override_language_settings {
12009                diff_options.max_word_diff_len = 0;
12010                diff_options.max_word_diff_line_count = 0;
12011            } else {
12012                diff_options.max_word_diff_len = usize::MAX;
12013                diff_options.max_word_diff_line_count = usize::MAX;
12014            }
12015
12016            for (old_range, new_text) in
12017                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12018            {
12019                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12020                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12021                edits.push((edit_start..edit_end, new_text));
12022            }
12023
12024            rewrapped_row_ranges.push(start_row..=end_row);
12025        }
12026
12027        self.buffer
12028            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12029    }
12030
12031    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12032        let mut text = String::new();
12033        let buffer = self.buffer.read(cx).snapshot(cx);
12034        let mut selections = self.selections.all::<Point>(cx);
12035        let mut clipboard_selections = Vec::with_capacity(selections.len());
12036        {
12037            let max_point = buffer.max_point();
12038            let mut is_first = true;
12039            for selection in &mut selections {
12040                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12041                if is_entire_line {
12042                    selection.start = Point::new(selection.start.row, 0);
12043                    if !selection.is_empty() && selection.end.column == 0 {
12044                        selection.end = cmp::min(max_point, selection.end);
12045                    } else {
12046                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12047                    }
12048                    selection.goal = SelectionGoal::None;
12049                }
12050                if is_first {
12051                    is_first = false;
12052                } else {
12053                    text += "\n";
12054                }
12055                let mut len = 0;
12056                for chunk in buffer.text_for_range(selection.start..selection.end) {
12057                    text.push_str(chunk);
12058                    len += chunk.len();
12059                }
12060                clipboard_selections.push(ClipboardSelection {
12061                    len,
12062                    is_entire_line,
12063                    first_line_indent: buffer
12064                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12065                        .len,
12066                });
12067            }
12068        }
12069
12070        self.transact(window, cx, |this, window, cx| {
12071            this.change_selections(Default::default(), window, cx, |s| {
12072                s.select(selections);
12073            });
12074            this.insert("", window, cx);
12075        });
12076        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12077    }
12078
12079    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12080        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12081        let item = self.cut_common(window, cx);
12082        cx.write_to_clipboard(item);
12083    }
12084
12085    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12086        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12087        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12088            s.move_with(|snapshot, sel| {
12089                if sel.is_empty() {
12090                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12091                }
12092            });
12093        });
12094        let item = self.cut_common(window, cx);
12095        cx.set_global(KillRing(item))
12096    }
12097
12098    pub fn kill_ring_yank(
12099        &mut self,
12100        _: &KillRingYank,
12101        window: &mut Window,
12102        cx: &mut Context<Self>,
12103    ) {
12104        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12105        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12106            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12107                (kill_ring.text().to_string(), kill_ring.metadata_json())
12108            } else {
12109                return;
12110            }
12111        } else {
12112            return;
12113        };
12114        self.do_paste(&text, metadata, false, window, cx);
12115    }
12116
12117    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12118        self.do_copy(true, cx);
12119    }
12120
12121    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12122        self.do_copy(false, cx);
12123    }
12124
12125    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12126        let selections = self.selections.all::<Point>(cx);
12127        let buffer = self.buffer.read(cx).read(cx);
12128        let mut text = String::new();
12129
12130        let mut clipboard_selections = Vec::with_capacity(selections.len());
12131        {
12132            let max_point = buffer.max_point();
12133            let mut is_first = true;
12134            for selection in &selections {
12135                let mut start = selection.start;
12136                let mut end = selection.end;
12137                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12138                if is_entire_line {
12139                    start = Point::new(start.row, 0);
12140                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12141                }
12142
12143                let mut trimmed_selections = Vec::new();
12144                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12145                    let row = MultiBufferRow(start.row);
12146                    let first_indent = buffer.indent_size_for_line(row);
12147                    if first_indent.len == 0 || start.column > first_indent.len {
12148                        trimmed_selections.push(start..end);
12149                    } else {
12150                        trimmed_selections.push(
12151                            Point::new(row.0, first_indent.len)
12152                                ..Point::new(row.0, buffer.line_len(row)),
12153                        );
12154                        for row in start.row + 1..=end.row {
12155                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12156                            if row == end.row {
12157                                line_len = end.column;
12158                            }
12159                            if line_len == 0 {
12160                                trimmed_selections
12161                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12162                                continue;
12163                            }
12164                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12165                            if row_indent_size.len >= first_indent.len {
12166                                trimmed_selections.push(
12167                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12168                                );
12169                            } else {
12170                                trimmed_selections.clear();
12171                                trimmed_selections.push(start..end);
12172                                break;
12173                            }
12174                        }
12175                    }
12176                } else {
12177                    trimmed_selections.push(start..end);
12178                }
12179
12180                for trimmed_range in trimmed_selections {
12181                    if is_first {
12182                        is_first = false;
12183                    } else {
12184                        text += "\n";
12185                    }
12186                    let mut len = 0;
12187                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12188                        text.push_str(chunk);
12189                        len += chunk.len();
12190                    }
12191                    clipboard_selections.push(ClipboardSelection {
12192                        len,
12193                        is_entire_line,
12194                        first_line_indent: buffer
12195                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12196                            .len,
12197                    });
12198                }
12199            }
12200        }
12201
12202        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12203            text,
12204            clipboard_selections,
12205        ));
12206    }
12207
12208    pub fn do_paste(
12209        &mut self,
12210        text: &String,
12211        clipboard_selections: Option<Vec<ClipboardSelection>>,
12212        handle_entire_lines: bool,
12213        window: &mut Window,
12214        cx: &mut Context<Self>,
12215    ) {
12216        if self.read_only(cx) {
12217            return;
12218        }
12219
12220        let clipboard_text = Cow::Borrowed(text);
12221
12222        self.transact(window, cx, |this, window, cx| {
12223            let had_active_edit_prediction = this.has_active_edit_prediction();
12224
12225            if let Some(mut clipboard_selections) = clipboard_selections {
12226                let old_selections = this.selections.all::<usize>(cx);
12227                let all_selections_were_entire_line =
12228                    clipboard_selections.iter().all(|s| s.is_entire_line);
12229                let first_selection_indent_column =
12230                    clipboard_selections.first().map(|s| s.first_line_indent);
12231                if clipboard_selections.len() != old_selections.len() {
12232                    clipboard_selections.drain(..);
12233                }
12234                let cursor_offset = this.selections.last::<usize>(cx).head();
12235                let mut auto_indent_on_paste = true;
12236
12237                this.buffer.update(cx, |buffer, cx| {
12238                    let snapshot = buffer.read(cx);
12239                    auto_indent_on_paste = snapshot
12240                        .language_settings_at(cursor_offset, cx)
12241                        .auto_indent_on_paste;
12242
12243                    let mut start_offset = 0;
12244                    let mut edits = Vec::new();
12245                    let mut original_indent_columns = Vec::new();
12246                    for (ix, selection) in old_selections.iter().enumerate() {
12247                        let to_insert;
12248                        let entire_line;
12249                        let original_indent_column;
12250                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12251                            let end_offset = start_offset + clipboard_selection.len;
12252                            to_insert = &clipboard_text[start_offset..end_offset];
12253                            entire_line = clipboard_selection.is_entire_line;
12254                            start_offset = end_offset + 1;
12255                            original_indent_column = Some(clipboard_selection.first_line_indent);
12256                        } else {
12257                            to_insert = clipboard_text.as_str();
12258                            entire_line = all_selections_were_entire_line;
12259                            original_indent_column = first_selection_indent_column
12260                        }
12261
12262                        // If the corresponding selection was empty when this slice of the
12263                        // clipboard text was written, then the entire line containing the
12264                        // selection was copied. If this selection is also currently empty,
12265                        // then paste the line before the current line of the buffer.
12266                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12267                            let column = selection.start.to_point(&snapshot).column as usize;
12268                            let line_start = selection.start - column;
12269                            line_start..line_start
12270                        } else {
12271                            selection.range()
12272                        };
12273
12274                        edits.push((range, to_insert));
12275                        original_indent_columns.push(original_indent_column);
12276                    }
12277                    drop(snapshot);
12278
12279                    buffer.edit(
12280                        edits,
12281                        if auto_indent_on_paste {
12282                            Some(AutoindentMode::Block {
12283                                original_indent_columns,
12284                            })
12285                        } else {
12286                            None
12287                        },
12288                        cx,
12289                    );
12290                });
12291
12292                let selections = this.selections.all::<usize>(cx);
12293                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12294            } else {
12295                this.insert(&clipboard_text, window, cx);
12296            }
12297
12298            let trigger_in_words =
12299                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12300
12301            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12302        });
12303    }
12304
12305    pub fn diff_clipboard_with_selection(
12306        &mut self,
12307        _: &DiffClipboardWithSelection,
12308        window: &mut Window,
12309        cx: &mut Context<Self>,
12310    ) {
12311        let selections = self.selections.all::<usize>(cx);
12312
12313        if selections.is_empty() {
12314            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12315            return;
12316        };
12317
12318        let clipboard_text = match cx.read_from_clipboard() {
12319            Some(item) => match item.entries().first() {
12320                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12321                _ => None,
12322            },
12323            None => None,
12324        };
12325
12326        let Some(clipboard_text) = clipboard_text else {
12327            log::warn!("Clipboard doesn't contain text.");
12328            return;
12329        };
12330
12331        window.dispatch_action(
12332            Box::new(DiffClipboardWithSelectionData {
12333                clipboard_text,
12334                editor: cx.entity(),
12335            }),
12336            cx,
12337        );
12338    }
12339
12340    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12341        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12342        if let Some(item) = cx.read_from_clipboard() {
12343            let entries = item.entries();
12344
12345            match entries.first() {
12346                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12347                // of all the pasted entries.
12348                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12349                    .do_paste(
12350                        clipboard_string.text(),
12351                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12352                        true,
12353                        window,
12354                        cx,
12355                    ),
12356                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12357            }
12358        }
12359    }
12360
12361    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12362        if self.read_only(cx) {
12363            return;
12364        }
12365
12366        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12367
12368        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12369            if let Some((selections, _)) =
12370                self.selection_history.transaction(transaction_id).cloned()
12371            {
12372                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12373                    s.select_anchors(selections.to_vec());
12374                });
12375            } else {
12376                log::error!(
12377                    "No entry in selection_history found for undo. \
12378                     This may correspond to a bug where undo does not update the selection. \
12379                     If this is occurring, please add details to \
12380                     https://github.com/zed-industries/zed/issues/22692"
12381                );
12382            }
12383            self.request_autoscroll(Autoscroll::fit(), cx);
12384            self.unmark_text(window, cx);
12385            self.refresh_edit_prediction(true, false, window, cx);
12386            cx.emit(EditorEvent::Edited { transaction_id });
12387            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12388        }
12389    }
12390
12391    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12392        if self.read_only(cx) {
12393            return;
12394        }
12395
12396        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12397
12398        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12399            if let Some((_, Some(selections))) =
12400                self.selection_history.transaction(transaction_id).cloned()
12401            {
12402                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12403                    s.select_anchors(selections.to_vec());
12404                });
12405            } else {
12406                log::error!(
12407                    "No entry in selection_history found for redo. \
12408                     This may correspond to a bug where undo does not update the selection. \
12409                     If this is occurring, please add details to \
12410                     https://github.com/zed-industries/zed/issues/22692"
12411                );
12412            }
12413            self.request_autoscroll(Autoscroll::fit(), cx);
12414            self.unmark_text(window, cx);
12415            self.refresh_edit_prediction(true, false, window, cx);
12416            cx.emit(EditorEvent::Edited { transaction_id });
12417        }
12418    }
12419
12420    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12421        self.buffer
12422            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12423    }
12424
12425    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12426        self.buffer
12427            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12428    }
12429
12430    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12431        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12432        self.change_selections(Default::default(), window, cx, |s| {
12433            s.move_with(|map, selection| {
12434                let cursor = if selection.is_empty() {
12435                    movement::left(map, selection.start)
12436                } else {
12437                    selection.start
12438                };
12439                selection.collapse_to(cursor, SelectionGoal::None);
12440            });
12441        })
12442    }
12443
12444    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12445        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12446        self.change_selections(Default::default(), window, cx, |s| {
12447            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12448        })
12449    }
12450
12451    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12453        self.change_selections(Default::default(), window, cx, |s| {
12454            s.move_with(|map, selection| {
12455                let cursor = if selection.is_empty() {
12456                    movement::right(map, selection.end)
12457                } else {
12458                    selection.end
12459                };
12460                selection.collapse_to(cursor, SelectionGoal::None)
12461            });
12462        })
12463    }
12464
12465    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12466        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12467        self.change_selections(Default::default(), window, cx, |s| {
12468            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12469        })
12470    }
12471
12472    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12473        if self.take_rename(true, window, cx).is_some() {
12474            return;
12475        }
12476
12477        if self.mode.is_single_line() {
12478            cx.propagate();
12479            return;
12480        }
12481
12482        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12483
12484        let text_layout_details = &self.text_layout_details(window);
12485        let selection_count = self.selections.count();
12486        let first_selection = self.selections.first_anchor();
12487
12488        self.change_selections(Default::default(), window, cx, |s| {
12489            s.move_with(|map, selection| {
12490                if !selection.is_empty() {
12491                    selection.goal = SelectionGoal::None;
12492                }
12493                let (cursor, goal) = movement::up(
12494                    map,
12495                    selection.start,
12496                    selection.goal,
12497                    false,
12498                    text_layout_details,
12499                );
12500                selection.collapse_to(cursor, goal);
12501            });
12502        });
12503
12504        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12505        {
12506            cx.propagate();
12507        }
12508    }
12509
12510    pub fn move_up_by_lines(
12511        &mut self,
12512        action: &MoveUpByLines,
12513        window: &mut Window,
12514        cx: &mut Context<Self>,
12515    ) {
12516        if self.take_rename(true, window, cx).is_some() {
12517            return;
12518        }
12519
12520        if self.mode.is_single_line() {
12521            cx.propagate();
12522            return;
12523        }
12524
12525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12526
12527        let text_layout_details = &self.text_layout_details(window);
12528
12529        self.change_selections(Default::default(), window, cx, |s| {
12530            s.move_with(|map, selection| {
12531                if !selection.is_empty() {
12532                    selection.goal = SelectionGoal::None;
12533                }
12534                let (cursor, goal) = movement::up_by_rows(
12535                    map,
12536                    selection.start,
12537                    action.lines,
12538                    selection.goal,
12539                    false,
12540                    text_layout_details,
12541                );
12542                selection.collapse_to(cursor, goal);
12543            });
12544        })
12545    }
12546
12547    pub fn move_down_by_lines(
12548        &mut self,
12549        action: &MoveDownByLines,
12550        window: &mut Window,
12551        cx: &mut Context<Self>,
12552    ) {
12553        if self.take_rename(true, window, cx).is_some() {
12554            return;
12555        }
12556
12557        if self.mode.is_single_line() {
12558            cx.propagate();
12559            return;
12560        }
12561
12562        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12563
12564        let text_layout_details = &self.text_layout_details(window);
12565
12566        self.change_selections(Default::default(), window, cx, |s| {
12567            s.move_with(|map, selection| {
12568                if !selection.is_empty() {
12569                    selection.goal = SelectionGoal::None;
12570                }
12571                let (cursor, goal) = movement::down_by_rows(
12572                    map,
12573                    selection.start,
12574                    action.lines,
12575                    selection.goal,
12576                    false,
12577                    text_layout_details,
12578                );
12579                selection.collapse_to(cursor, goal);
12580            });
12581        })
12582    }
12583
12584    pub fn select_down_by_lines(
12585        &mut self,
12586        action: &SelectDownByLines,
12587        window: &mut Window,
12588        cx: &mut Context<Self>,
12589    ) {
12590        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12591        let text_layout_details = &self.text_layout_details(window);
12592        self.change_selections(Default::default(), window, cx, |s| {
12593            s.move_heads_with(|map, head, goal| {
12594                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12595            })
12596        })
12597    }
12598
12599    pub fn select_up_by_lines(
12600        &mut self,
12601        action: &SelectUpByLines,
12602        window: &mut Window,
12603        cx: &mut Context<Self>,
12604    ) {
12605        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12606        let text_layout_details = &self.text_layout_details(window);
12607        self.change_selections(Default::default(), window, cx, |s| {
12608            s.move_heads_with(|map, head, goal| {
12609                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12610            })
12611        })
12612    }
12613
12614    pub fn select_page_up(
12615        &mut self,
12616        _: &SelectPageUp,
12617        window: &mut Window,
12618        cx: &mut Context<Self>,
12619    ) {
12620        let Some(row_count) = self.visible_row_count() else {
12621            return;
12622        };
12623
12624        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12625
12626        let text_layout_details = &self.text_layout_details(window);
12627
12628        self.change_selections(Default::default(), window, cx, |s| {
12629            s.move_heads_with(|map, head, goal| {
12630                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12631            })
12632        })
12633    }
12634
12635    pub fn move_page_up(
12636        &mut self,
12637        action: &MovePageUp,
12638        window: &mut Window,
12639        cx: &mut Context<Self>,
12640    ) {
12641        if self.take_rename(true, window, cx).is_some() {
12642            return;
12643        }
12644
12645        if self
12646            .context_menu
12647            .borrow_mut()
12648            .as_mut()
12649            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12650            .unwrap_or(false)
12651        {
12652            return;
12653        }
12654
12655        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12656            cx.propagate();
12657            return;
12658        }
12659
12660        let Some(row_count) = self.visible_row_count() else {
12661            return;
12662        };
12663
12664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12665
12666        let effects = if action.center_cursor {
12667            SelectionEffects::scroll(Autoscroll::center())
12668        } else {
12669            SelectionEffects::default()
12670        };
12671
12672        let text_layout_details = &self.text_layout_details(window);
12673
12674        self.change_selections(effects, window, cx, |s| {
12675            s.move_with(|map, selection| {
12676                if !selection.is_empty() {
12677                    selection.goal = SelectionGoal::None;
12678                }
12679                let (cursor, goal) = movement::up_by_rows(
12680                    map,
12681                    selection.end,
12682                    row_count,
12683                    selection.goal,
12684                    false,
12685                    text_layout_details,
12686                );
12687                selection.collapse_to(cursor, goal);
12688            });
12689        });
12690    }
12691
12692    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12693        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12694        let text_layout_details = &self.text_layout_details(window);
12695        self.change_selections(Default::default(), window, cx, |s| {
12696            s.move_heads_with(|map, head, goal| {
12697                movement::up(map, head, goal, false, text_layout_details)
12698            })
12699        })
12700    }
12701
12702    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12703        self.take_rename(true, window, cx);
12704
12705        if self.mode.is_single_line() {
12706            cx.propagate();
12707            return;
12708        }
12709
12710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12711
12712        let text_layout_details = &self.text_layout_details(window);
12713        let selection_count = self.selections.count();
12714        let first_selection = self.selections.first_anchor();
12715
12716        self.change_selections(Default::default(), window, cx, |s| {
12717            s.move_with(|map, selection| {
12718                if !selection.is_empty() {
12719                    selection.goal = SelectionGoal::None;
12720                }
12721                let (cursor, goal) = movement::down(
12722                    map,
12723                    selection.end,
12724                    selection.goal,
12725                    false,
12726                    text_layout_details,
12727                );
12728                selection.collapse_to(cursor, goal);
12729            });
12730        });
12731
12732        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12733        {
12734            cx.propagate();
12735        }
12736    }
12737
12738    pub fn select_page_down(
12739        &mut self,
12740        _: &SelectPageDown,
12741        window: &mut Window,
12742        cx: &mut Context<Self>,
12743    ) {
12744        let Some(row_count) = self.visible_row_count() else {
12745            return;
12746        };
12747
12748        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12749
12750        let text_layout_details = &self.text_layout_details(window);
12751
12752        self.change_selections(Default::default(), window, cx, |s| {
12753            s.move_heads_with(|map, head, goal| {
12754                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12755            })
12756        })
12757    }
12758
12759    pub fn move_page_down(
12760        &mut self,
12761        action: &MovePageDown,
12762        window: &mut Window,
12763        cx: &mut Context<Self>,
12764    ) {
12765        if self.take_rename(true, window, cx).is_some() {
12766            return;
12767        }
12768
12769        if self
12770            .context_menu
12771            .borrow_mut()
12772            .as_mut()
12773            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12774            .unwrap_or(false)
12775        {
12776            return;
12777        }
12778
12779        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12780            cx.propagate();
12781            return;
12782        }
12783
12784        let Some(row_count) = self.visible_row_count() else {
12785            return;
12786        };
12787
12788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12789
12790        let effects = if action.center_cursor {
12791            SelectionEffects::scroll(Autoscroll::center())
12792        } else {
12793            SelectionEffects::default()
12794        };
12795
12796        let text_layout_details = &self.text_layout_details(window);
12797        self.change_selections(effects, window, cx, |s| {
12798            s.move_with(|map, selection| {
12799                if !selection.is_empty() {
12800                    selection.goal = SelectionGoal::None;
12801                }
12802                let (cursor, goal) = movement::down_by_rows(
12803                    map,
12804                    selection.end,
12805                    row_count,
12806                    selection.goal,
12807                    false,
12808                    text_layout_details,
12809                );
12810                selection.collapse_to(cursor, goal);
12811            });
12812        });
12813    }
12814
12815    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12816        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12817        let text_layout_details = &self.text_layout_details(window);
12818        self.change_selections(Default::default(), window, cx, |s| {
12819            s.move_heads_with(|map, head, goal| {
12820                movement::down(map, head, goal, false, text_layout_details)
12821            })
12822        });
12823    }
12824
12825    pub fn context_menu_first(
12826        &mut self,
12827        _: &ContextMenuFirst,
12828        window: &mut Window,
12829        cx: &mut Context<Self>,
12830    ) {
12831        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12832            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12833        }
12834    }
12835
12836    pub fn context_menu_prev(
12837        &mut self,
12838        _: &ContextMenuPrevious,
12839        window: &mut Window,
12840        cx: &mut Context<Self>,
12841    ) {
12842        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12843            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12844        }
12845    }
12846
12847    pub fn context_menu_next(
12848        &mut self,
12849        _: &ContextMenuNext,
12850        window: &mut Window,
12851        cx: &mut Context<Self>,
12852    ) {
12853        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12854            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12855        }
12856    }
12857
12858    pub fn context_menu_last(
12859        &mut self,
12860        _: &ContextMenuLast,
12861        window: &mut Window,
12862        cx: &mut Context<Self>,
12863    ) {
12864        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12865            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12866        }
12867    }
12868
12869    pub fn signature_help_prev(
12870        &mut self,
12871        _: &SignatureHelpPrevious,
12872        _: &mut Window,
12873        cx: &mut Context<Self>,
12874    ) {
12875        if let Some(popover) = self.signature_help_state.popover_mut() {
12876            if popover.current_signature == 0 {
12877                popover.current_signature = popover.signatures.len() - 1;
12878            } else {
12879                popover.current_signature -= 1;
12880            }
12881            cx.notify();
12882        }
12883    }
12884
12885    pub fn signature_help_next(
12886        &mut self,
12887        _: &SignatureHelpNext,
12888        _: &mut Window,
12889        cx: &mut Context<Self>,
12890    ) {
12891        if let Some(popover) = self.signature_help_state.popover_mut() {
12892            if popover.current_signature + 1 == popover.signatures.len() {
12893                popover.current_signature = 0;
12894            } else {
12895                popover.current_signature += 1;
12896            }
12897            cx.notify();
12898        }
12899    }
12900
12901    pub fn move_to_previous_word_start(
12902        &mut self,
12903        _: &MoveToPreviousWordStart,
12904        window: &mut Window,
12905        cx: &mut Context<Self>,
12906    ) {
12907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12908        self.change_selections(Default::default(), window, cx, |s| {
12909            s.move_cursors_with(|map, head, _| {
12910                (
12911                    movement::previous_word_start(map, head),
12912                    SelectionGoal::None,
12913                )
12914            });
12915        })
12916    }
12917
12918    pub fn move_to_previous_subword_start(
12919        &mut self,
12920        _: &MoveToPreviousSubwordStart,
12921        window: &mut Window,
12922        cx: &mut Context<Self>,
12923    ) {
12924        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12925        self.change_selections(Default::default(), window, cx, |s| {
12926            s.move_cursors_with(|map, head, _| {
12927                (
12928                    movement::previous_subword_start(map, head),
12929                    SelectionGoal::None,
12930                )
12931            });
12932        })
12933    }
12934
12935    pub fn select_to_previous_word_start(
12936        &mut self,
12937        _: &SelectToPreviousWordStart,
12938        window: &mut Window,
12939        cx: &mut Context<Self>,
12940    ) {
12941        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12942        self.change_selections(Default::default(), window, cx, |s| {
12943            s.move_heads_with(|map, head, _| {
12944                (
12945                    movement::previous_word_start(map, head),
12946                    SelectionGoal::None,
12947                )
12948            });
12949        })
12950    }
12951
12952    pub fn select_to_previous_subword_start(
12953        &mut self,
12954        _: &SelectToPreviousSubwordStart,
12955        window: &mut Window,
12956        cx: &mut Context<Self>,
12957    ) {
12958        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12959        self.change_selections(Default::default(), window, cx, |s| {
12960            s.move_heads_with(|map, head, _| {
12961                (
12962                    movement::previous_subword_start(map, head),
12963                    SelectionGoal::None,
12964                )
12965            });
12966        })
12967    }
12968
12969    pub fn delete_to_previous_word_start(
12970        &mut self,
12971        action: &DeleteToPreviousWordStart,
12972        window: &mut Window,
12973        cx: &mut Context<Self>,
12974    ) {
12975        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12976        self.transact(window, cx, |this, window, cx| {
12977            this.select_autoclose_pair(window, cx);
12978            this.change_selections(Default::default(), window, cx, |s| {
12979                s.move_with(|map, selection| {
12980                    if selection.is_empty() {
12981                        let cursor = if action.ignore_newlines {
12982                            movement::previous_word_start(map, selection.head())
12983                        } else {
12984                            movement::previous_word_start_or_newline(map, selection.head())
12985                        };
12986                        selection.set_head(cursor, SelectionGoal::None);
12987                    }
12988                });
12989            });
12990            this.insert("", window, cx);
12991        });
12992    }
12993
12994    pub fn delete_to_previous_subword_start(
12995        &mut self,
12996        _: &DeleteToPreviousSubwordStart,
12997        window: &mut Window,
12998        cx: &mut Context<Self>,
12999    ) {
13000        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13001        self.transact(window, cx, |this, window, cx| {
13002            this.select_autoclose_pair(window, cx);
13003            this.change_selections(Default::default(), window, cx, |s| {
13004                s.move_with(|map, selection| {
13005                    if selection.is_empty() {
13006                        let cursor = movement::previous_subword_start(map, selection.head());
13007                        selection.set_head(cursor, SelectionGoal::None);
13008                    }
13009                });
13010            });
13011            this.insert("", window, cx);
13012        });
13013    }
13014
13015    pub fn move_to_next_word_end(
13016        &mut self,
13017        _: &MoveToNextWordEnd,
13018        window: &mut Window,
13019        cx: &mut Context<Self>,
13020    ) {
13021        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13022        self.change_selections(Default::default(), window, cx, |s| {
13023            s.move_cursors_with(|map, head, _| {
13024                (movement::next_word_end(map, head), SelectionGoal::None)
13025            });
13026        })
13027    }
13028
13029    pub fn move_to_next_subword_end(
13030        &mut self,
13031        _: &MoveToNextSubwordEnd,
13032        window: &mut Window,
13033        cx: &mut Context<Self>,
13034    ) {
13035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13036        self.change_selections(Default::default(), window, cx, |s| {
13037            s.move_cursors_with(|map, head, _| {
13038                (movement::next_subword_end(map, head), SelectionGoal::None)
13039            });
13040        })
13041    }
13042
13043    pub fn select_to_next_word_end(
13044        &mut self,
13045        _: &SelectToNextWordEnd,
13046        window: &mut Window,
13047        cx: &mut Context<Self>,
13048    ) {
13049        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13050        self.change_selections(Default::default(), window, cx, |s| {
13051            s.move_heads_with(|map, head, _| {
13052                (movement::next_word_end(map, head), SelectionGoal::None)
13053            });
13054        })
13055    }
13056
13057    pub fn select_to_next_subword_end(
13058        &mut self,
13059        _: &SelectToNextSubwordEnd,
13060        window: &mut Window,
13061        cx: &mut Context<Self>,
13062    ) {
13063        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13064        self.change_selections(Default::default(), window, cx, |s| {
13065            s.move_heads_with(|map, head, _| {
13066                (movement::next_subword_end(map, head), SelectionGoal::None)
13067            });
13068        })
13069    }
13070
13071    pub fn delete_to_next_word_end(
13072        &mut self,
13073        action: &DeleteToNextWordEnd,
13074        window: &mut Window,
13075        cx: &mut Context<Self>,
13076    ) {
13077        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13078        self.transact(window, cx, |this, window, cx| {
13079            this.change_selections(Default::default(), window, cx, |s| {
13080                s.move_with(|map, selection| {
13081                    if selection.is_empty() {
13082                        let cursor = if action.ignore_newlines {
13083                            movement::next_word_end(map, selection.head())
13084                        } else {
13085                            movement::next_word_end_or_newline(map, selection.head())
13086                        };
13087                        selection.set_head(cursor, SelectionGoal::None);
13088                    }
13089                });
13090            });
13091            this.insert("", window, cx);
13092        });
13093    }
13094
13095    pub fn delete_to_next_subword_end(
13096        &mut self,
13097        _: &DeleteToNextSubwordEnd,
13098        window: &mut Window,
13099        cx: &mut Context<Self>,
13100    ) {
13101        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13102        self.transact(window, cx, |this, window, cx| {
13103            this.change_selections(Default::default(), window, cx, |s| {
13104                s.move_with(|map, selection| {
13105                    if selection.is_empty() {
13106                        let cursor = movement::next_subword_end(map, selection.head());
13107                        selection.set_head(cursor, SelectionGoal::None);
13108                    }
13109                });
13110            });
13111            this.insert("", window, cx);
13112        });
13113    }
13114
13115    pub fn move_to_beginning_of_line(
13116        &mut self,
13117        action: &MoveToBeginningOfLine,
13118        window: &mut Window,
13119        cx: &mut Context<Self>,
13120    ) {
13121        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13122        self.change_selections(Default::default(), window, cx, |s| {
13123            s.move_cursors_with(|map, head, _| {
13124                (
13125                    movement::indented_line_beginning(
13126                        map,
13127                        head,
13128                        action.stop_at_soft_wraps,
13129                        action.stop_at_indent,
13130                    ),
13131                    SelectionGoal::None,
13132                )
13133            });
13134        })
13135    }
13136
13137    pub fn select_to_beginning_of_line(
13138        &mut self,
13139        action: &SelectToBeginningOfLine,
13140        window: &mut Window,
13141        cx: &mut Context<Self>,
13142    ) {
13143        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13144        self.change_selections(Default::default(), window, cx, |s| {
13145            s.move_heads_with(|map, head, _| {
13146                (
13147                    movement::indented_line_beginning(
13148                        map,
13149                        head,
13150                        action.stop_at_soft_wraps,
13151                        action.stop_at_indent,
13152                    ),
13153                    SelectionGoal::None,
13154                )
13155            });
13156        });
13157    }
13158
13159    pub fn delete_to_beginning_of_line(
13160        &mut self,
13161        action: &DeleteToBeginningOfLine,
13162        window: &mut Window,
13163        cx: &mut Context<Self>,
13164    ) {
13165        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13166        self.transact(window, cx, |this, window, cx| {
13167            this.change_selections(Default::default(), window, cx, |s| {
13168                s.move_with(|_, selection| {
13169                    selection.reversed = true;
13170                });
13171            });
13172
13173            this.select_to_beginning_of_line(
13174                &SelectToBeginningOfLine {
13175                    stop_at_soft_wraps: false,
13176                    stop_at_indent: action.stop_at_indent,
13177                },
13178                window,
13179                cx,
13180            );
13181            this.backspace(&Backspace, window, cx);
13182        });
13183    }
13184
13185    pub fn move_to_end_of_line(
13186        &mut self,
13187        action: &MoveToEndOfLine,
13188        window: &mut Window,
13189        cx: &mut Context<Self>,
13190    ) {
13191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13192        self.change_selections(Default::default(), window, cx, |s| {
13193            s.move_cursors_with(|map, head, _| {
13194                (
13195                    movement::line_end(map, head, action.stop_at_soft_wraps),
13196                    SelectionGoal::None,
13197                )
13198            });
13199        })
13200    }
13201
13202    pub fn select_to_end_of_line(
13203        &mut self,
13204        action: &SelectToEndOfLine,
13205        window: &mut Window,
13206        cx: &mut Context<Self>,
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::line_end(map, head, action.stop_at_soft_wraps),
13213                    SelectionGoal::None,
13214                )
13215            });
13216        })
13217    }
13218
13219    pub fn delete_to_end_of_line(
13220        &mut self,
13221        _: &DeleteToEndOfLine,
13222        window: &mut Window,
13223        cx: &mut Context<Self>,
13224    ) {
13225        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13226        self.transact(window, cx, |this, window, cx| {
13227            this.select_to_end_of_line(
13228                &SelectToEndOfLine {
13229                    stop_at_soft_wraps: false,
13230                },
13231                window,
13232                cx,
13233            );
13234            this.delete(&Delete, window, cx);
13235        });
13236    }
13237
13238    pub fn cut_to_end_of_line(
13239        &mut self,
13240        _: &CutToEndOfLine,
13241        window: &mut Window,
13242        cx: &mut Context<Self>,
13243    ) {
13244        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13245        self.transact(window, cx, |this, window, cx| {
13246            this.select_to_end_of_line(
13247                &SelectToEndOfLine {
13248                    stop_at_soft_wraps: false,
13249                },
13250                window,
13251                cx,
13252            );
13253            this.cut(&Cut, window, cx);
13254        });
13255    }
13256
13257    pub fn move_to_start_of_paragraph(
13258        &mut self,
13259        _: &MoveToStartOfParagraph,
13260        window: &mut Window,
13261        cx: &mut Context<Self>,
13262    ) {
13263        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13264            cx.propagate();
13265            return;
13266        }
13267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13268        self.change_selections(Default::default(), window, cx, |s| {
13269            s.move_with(|map, selection| {
13270                selection.collapse_to(
13271                    movement::start_of_paragraph(map, selection.head(), 1),
13272                    SelectionGoal::None,
13273                )
13274            });
13275        })
13276    }
13277
13278    pub fn move_to_end_of_paragraph(
13279        &mut self,
13280        _: &MoveToEndOfParagraph,
13281        window: &mut Window,
13282        cx: &mut Context<Self>,
13283    ) {
13284        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13285            cx.propagate();
13286            return;
13287        }
13288        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13289        self.change_selections(Default::default(), window, cx, |s| {
13290            s.move_with(|map, selection| {
13291                selection.collapse_to(
13292                    movement::end_of_paragraph(map, selection.head(), 1),
13293                    SelectionGoal::None,
13294                )
13295            });
13296        })
13297    }
13298
13299    pub fn select_to_start_of_paragraph(
13300        &mut self,
13301        _: &SelectToStartOfParagraph,
13302        window: &mut Window,
13303        cx: &mut Context<Self>,
13304    ) {
13305        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13306            cx.propagate();
13307            return;
13308        }
13309        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13310        self.change_selections(Default::default(), window, cx, |s| {
13311            s.move_heads_with(|map, head, _| {
13312                (
13313                    movement::start_of_paragraph(map, head, 1),
13314                    SelectionGoal::None,
13315                )
13316            });
13317        })
13318    }
13319
13320    pub fn select_to_end_of_paragraph(
13321        &mut self,
13322        _: &SelectToEndOfParagraph,
13323        window: &mut Window,
13324        cx: &mut Context<Self>,
13325    ) {
13326        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13327            cx.propagate();
13328            return;
13329        }
13330        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13331        self.change_selections(Default::default(), window, cx, |s| {
13332            s.move_heads_with(|map, head, _| {
13333                (
13334                    movement::end_of_paragraph(map, head, 1),
13335                    SelectionGoal::None,
13336                )
13337            });
13338        })
13339    }
13340
13341    pub fn move_to_start_of_excerpt(
13342        &mut self,
13343        _: &MoveToStartOfExcerpt,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) {
13347        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13348            cx.propagate();
13349            return;
13350        }
13351        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13352        self.change_selections(Default::default(), window, cx, |s| {
13353            s.move_with(|map, selection| {
13354                selection.collapse_to(
13355                    movement::start_of_excerpt(
13356                        map,
13357                        selection.head(),
13358                        workspace::searchable::Direction::Prev,
13359                    ),
13360                    SelectionGoal::None,
13361                )
13362            });
13363        })
13364    }
13365
13366    pub fn move_to_start_of_next_excerpt(
13367        &mut self,
13368        _: &MoveToStartOfNextExcerpt,
13369        window: &mut Window,
13370        cx: &mut Context<Self>,
13371    ) {
13372        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13373            cx.propagate();
13374            return;
13375        }
13376
13377        self.change_selections(Default::default(), window, cx, |s| {
13378            s.move_with(|map, selection| {
13379                selection.collapse_to(
13380                    movement::start_of_excerpt(
13381                        map,
13382                        selection.head(),
13383                        workspace::searchable::Direction::Next,
13384                    ),
13385                    SelectionGoal::None,
13386                )
13387            });
13388        })
13389    }
13390
13391    pub fn move_to_end_of_excerpt(
13392        &mut self,
13393        _: &MoveToEndOfExcerpt,
13394        window: &mut Window,
13395        cx: &mut Context<Self>,
13396    ) {
13397        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13398            cx.propagate();
13399            return;
13400        }
13401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13402        self.change_selections(Default::default(), window, cx, |s| {
13403            s.move_with(|map, selection| {
13404                selection.collapse_to(
13405                    movement::end_of_excerpt(
13406                        map,
13407                        selection.head(),
13408                        workspace::searchable::Direction::Next,
13409                    ),
13410                    SelectionGoal::None,
13411                )
13412            });
13413        })
13414    }
13415
13416    pub fn move_to_end_of_previous_excerpt(
13417        &mut self,
13418        _: &MoveToEndOfPreviousExcerpt,
13419        window: &mut Window,
13420        cx: &mut Context<Self>,
13421    ) {
13422        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13423            cx.propagate();
13424            return;
13425        }
13426        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13427        self.change_selections(Default::default(), window, cx, |s| {
13428            s.move_with(|map, selection| {
13429                selection.collapse_to(
13430                    movement::end_of_excerpt(
13431                        map,
13432                        selection.head(),
13433                        workspace::searchable::Direction::Prev,
13434                    ),
13435                    SelectionGoal::None,
13436                )
13437            });
13438        })
13439    }
13440
13441    pub fn select_to_start_of_excerpt(
13442        &mut self,
13443        _: &SelectToStartOfExcerpt,
13444        window: &mut Window,
13445        cx: &mut Context<Self>,
13446    ) {
13447        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13448            cx.propagate();
13449            return;
13450        }
13451        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13452        self.change_selections(Default::default(), window, cx, |s| {
13453            s.move_heads_with(|map, head, _| {
13454                (
13455                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13456                    SelectionGoal::None,
13457                )
13458            });
13459        })
13460    }
13461
13462    pub fn select_to_start_of_next_excerpt(
13463        &mut self,
13464        _: &SelectToStartOfNextExcerpt,
13465        window: &mut Window,
13466        cx: &mut Context<Self>,
13467    ) {
13468        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13469            cx.propagate();
13470            return;
13471        }
13472        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13473        self.change_selections(Default::default(), window, cx, |s| {
13474            s.move_heads_with(|map, head, _| {
13475                (
13476                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13477                    SelectionGoal::None,
13478                )
13479            });
13480        })
13481    }
13482
13483    pub fn select_to_end_of_excerpt(
13484        &mut self,
13485        _: &SelectToEndOfExcerpt,
13486        window: &mut Window,
13487        cx: &mut Context<Self>,
13488    ) {
13489        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13490            cx.propagate();
13491            return;
13492        }
13493        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13494        self.change_selections(Default::default(), window, cx, |s| {
13495            s.move_heads_with(|map, head, _| {
13496                (
13497                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13498                    SelectionGoal::None,
13499                )
13500            });
13501        })
13502    }
13503
13504    pub fn select_to_end_of_previous_excerpt(
13505        &mut self,
13506        _: &SelectToEndOfPreviousExcerpt,
13507        window: &mut Window,
13508        cx: &mut Context<Self>,
13509    ) {
13510        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13511            cx.propagate();
13512            return;
13513        }
13514        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13515        self.change_selections(Default::default(), window, cx, |s| {
13516            s.move_heads_with(|map, head, _| {
13517                (
13518                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13519                    SelectionGoal::None,
13520                )
13521            });
13522        })
13523    }
13524
13525    pub fn move_to_beginning(
13526        &mut self,
13527        _: &MoveToBeginning,
13528        window: &mut Window,
13529        cx: &mut Context<Self>,
13530    ) {
13531        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13532            cx.propagate();
13533            return;
13534        }
13535        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13536        self.change_selections(Default::default(), window, cx, |s| {
13537            s.select_ranges(vec![0..0]);
13538        });
13539    }
13540
13541    pub fn select_to_beginning(
13542        &mut self,
13543        _: &SelectToBeginning,
13544        window: &mut Window,
13545        cx: &mut Context<Self>,
13546    ) {
13547        let mut selection = self.selections.last::<Point>(cx);
13548        selection.set_head(Point::zero(), SelectionGoal::None);
13549        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13550        self.change_selections(Default::default(), window, cx, |s| {
13551            s.select(vec![selection]);
13552        });
13553    }
13554
13555    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13556        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13557            cx.propagate();
13558            return;
13559        }
13560        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13561        let cursor = self.buffer.read(cx).read(cx).len();
13562        self.change_selections(Default::default(), window, cx, |s| {
13563            s.select_ranges(vec![cursor..cursor])
13564        });
13565    }
13566
13567    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13568        self.nav_history = nav_history;
13569    }
13570
13571    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13572        self.nav_history.as_ref()
13573    }
13574
13575    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13576        self.push_to_nav_history(
13577            self.selections.newest_anchor().head(),
13578            None,
13579            false,
13580            true,
13581            cx,
13582        );
13583    }
13584
13585    fn push_to_nav_history(
13586        &mut self,
13587        cursor_anchor: Anchor,
13588        new_position: Option<Point>,
13589        is_deactivate: bool,
13590        always: bool,
13591        cx: &mut Context<Self>,
13592    ) {
13593        if let Some(nav_history) = self.nav_history.as_mut() {
13594            let buffer = self.buffer.read(cx).read(cx);
13595            let cursor_position = cursor_anchor.to_point(&buffer);
13596            let scroll_state = self.scroll_manager.anchor();
13597            let scroll_top_row = scroll_state.top_row(&buffer);
13598            drop(buffer);
13599
13600            if let Some(new_position) = new_position {
13601                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13602                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13603                    return;
13604                }
13605            }
13606
13607            nav_history.push(
13608                Some(NavigationData {
13609                    cursor_anchor,
13610                    cursor_position,
13611                    scroll_anchor: scroll_state,
13612                    scroll_top_row,
13613                }),
13614                cx,
13615            );
13616            cx.emit(EditorEvent::PushedToNavHistory {
13617                anchor: cursor_anchor,
13618                is_deactivate,
13619            })
13620        }
13621    }
13622
13623    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13624        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13625        let buffer = self.buffer.read(cx).snapshot(cx);
13626        let mut selection = self.selections.first::<usize>(cx);
13627        selection.set_head(buffer.len(), SelectionGoal::None);
13628        self.change_selections(Default::default(), window, cx, |s| {
13629            s.select(vec![selection]);
13630        });
13631    }
13632
13633    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13634        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13635        let end = self.buffer.read(cx).read(cx).len();
13636        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13637            s.select_ranges(vec![0..end]);
13638        });
13639    }
13640
13641    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13643        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13644        let mut selections = self.selections.all::<Point>(cx);
13645        let max_point = display_map.buffer_snapshot.max_point();
13646        for selection in &mut selections {
13647            let rows = selection.spanned_rows(true, &display_map);
13648            selection.start = Point::new(rows.start.0, 0);
13649            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13650            selection.reversed = false;
13651        }
13652        self.change_selections(Default::default(), window, cx, |s| {
13653            s.select(selections);
13654        });
13655    }
13656
13657    pub fn split_selection_into_lines(
13658        &mut self,
13659        action: &SplitSelectionIntoLines,
13660        window: &mut Window,
13661        cx: &mut Context<Self>,
13662    ) {
13663        let selections = self
13664            .selections
13665            .all::<Point>(cx)
13666            .into_iter()
13667            .map(|selection| selection.start..selection.end)
13668            .collect::<Vec<_>>();
13669        self.unfold_ranges(&selections, true, true, cx);
13670
13671        let mut new_selection_ranges = Vec::new();
13672        {
13673            let buffer = self.buffer.read(cx).read(cx);
13674            for selection in selections {
13675                for row in selection.start.row..selection.end.row {
13676                    let line_start = Point::new(row, 0);
13677                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13678
13679                    if action.keep_selections {
13680                        // Keep the selection range for each line
13681                        let selection_start = if row == selection.start.row {
13682                            selection.start
13683                        } else {
13684                            line_start
13685                        };
13686                        new_selection_ranges.push(selection_start..line_end);
13687                    } else {
13688                        // Collapse to cursor at end of line
13689                        new_selection_ranges.push(line_end..line_end);
13690                    }
13691                }
13692
13693                let is_multiline_selection = selection.start.row != selection.end.row;
13694                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13695                // so this action feels more ergonomic when paired with other selection operations
13696                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13697                if !should_skip_last {
13698                    if action.keep_selections {
13699                        if is_multiline_selection {
13700                            let line_start = Point::new(selection.end.row, 0);
13701                            new_selection_ranges.push(line_start..selection.end);
13702                        } else {
13703                            new_selection_ranges.push(selection.start..selection.end);
13704                        }
13705                    } else {
13706                        new_selection_ranges.push(selection.end..selection.end);
13707                    }
13708                }
13709            }
13710        }
13711        self.change_selections(Default::default(), window, cx, |s| {
13712            s.select_ranges(new_selection_ranges);
13713        });
13714    }
13715
13716    pub fn add_selection_above(
13717        &mut self,
13718        _: &AddSelectionAbove,
13719        window: &mut Window,
13720        cx: &mut Context<Self>,
13721    ) {
13722        self.add_selection(true, window, cx);
13723    }
13724
13725    pub fn add_selection_below(
13726        &mut self,
13727        _: &AddSelectionBelow,
13728        window: &mut Window,
13729        cx: &mut Context<Self>,
13730    ) {
13731        self.add_selection(false, window, cx);
13732    }
13733
13734    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13736
13737        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13738        let all_selections = self.selections.all::<Point>(cx);
13739        let text_layout_details = self.text_layout_details(window);
13740
13741        let (mut columnar_selections, new_selections_to_columnarize) = {
13742            if let Some(state) = self.add_selections_state.as_ref() {
13743                let columnar_selection_ids: HashSet<_> = state
13744                    .groups
13745                    .iter()
13746                    .flat_map(|group| group.stack.iter())
13747                    .copied()
13748                    .collect();
13749
13750                all_selections
13751                    .into_iter()
13752                    .partition(|s| columnar_selection_ids.contains(&s.id))
13753            } else {
13754                (Vec::new(), all_selections)
13755            }
13756        };
13757
13758        let mut state = self
13759            .add_selections_state
13760            .take()
13761            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13762
13763        for selection in new_selections_to_columnarize {
13764            let range = selection.display_range(&display_map).sorted();
13765            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13766            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13767            let positions = start_x.min(end_x)..start_x.max(end_x);
13768            let mut stack = Vec::new();
13769            for row in range.start.row().0..=range.end.row().0 {
13770                if let Some(selection) = self.selections.build_columnar_selection(
13771                    &display_map,
13772                    DisplayRow(row),
13773                    &positions,
13774                    selection.reversed,
13775                    &text_layout_details,
13776                ) {
13777                    stack.push(selection.id);
13778                    columnar_selections.push(selection);
13779                }
13780            }
13781            if !stack.is_empty() {
13782                if above {
13783                    stack.reverse();
13784                }
13785                state.groups.push(AddSelectionsGroup { above, stack });
13786            }
13787        }
13788
13789        let mut final_selections = Vec::new();
13790        let end_row = if above {
13791            DisplayRow(0)
13792        } else {
13793            display_map.max_point().row()
13794        };
13795
13796        let mut last_added_item_per_group = HashMap::default();
13797        for group in state.groups.iter_mut() {
13798            if let Some(last_id) = group.stack.last() {
13799                last_added_item_per_group.insert(*last_id, group);
13800            }
13801        }
13802
13803        for selection in columnar_selections {
13804            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13805                if above == group.above {
13806                    let range = selection.display_range(&display_map).sorted();
13807                    debug_assert_eq!(range.start.row(), range.end.row());
13808                    let mut row = range.start.row();
13809                    let positions =
13810                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13811                            px(start)..px(end)
13812                        } else {
13813                            let start_x =
13814                                display_map.x_for_display_point(range.start, &text_layout_details);
13815                            let end_x =
13816                                display_map.x_for_display_point(range.end, &text_layout_details);
13817                            start_x.min(end_x)..start_x.max(end_x)
13818                        };
13819
13820                    let mut maybe_new_selection = None;
13821                    while row != end_row {
13822                        if above {
13823                            row.0 -= 1;
13824                        } else {
13825                            row.0 += 1;
13826                        }
13827                        if let Some(new_selection) = self.selections.build_columnar_selection(
13828                            &display_map,
13829                            row,
13830                            &positions,
13831                            selection.reversed,
13832                            &text_layout_details,
13833                        ) {
13834                            maybe_new_selection = Some(new_selection);
13835                            break;
13836                        }
13837                    }
13838
13839                    if let Some(new_selection) = maybe_new_selection {
13840                        group.stack.push(new_selection.id);
13841                        if above {
13842                            final_selections.push(new_selection);
13843                            final_selections.push(selection);
13844                        } else {
13845                            final_selections.push(selection);
13846                            final_selections.push(new_selection);
13847                        }
13848                    } else {
13849                        final_selections.push(selection);
13850                    }
13851                } else {
13852                    group.stack.pop();
13853                }
13854            } else {
13855                final_selections.push(selection);
13856            }
13857        }
13858
13859        self.change_selections(Default::default(), window, cx, |s| {
13860            s.select(final_selections);
13861        });
13862
13863        let final_selection_ids: HashSet<_> = self
13864            .selections
13865            .all::<Point>(cx)
13866            .iter()
13867            .map(|s| s.id)
13868            .collect();
13869        state.groups.retain_mut(|group| {
13870            // selections might get merged above so we remove invalid items from stacks
13871            group.stack.retain(|id| final_selection_ids.contains(id));
13872
13873            // single selection in stack can be treated as initial state
13874            group.stack.len() > 1
13875        });
13876
13877        if !state.groups.is_empty() {
13878            self.add_selections_state = Some(state);
13879        }
13880    }
13881
13882    fn select_match_ranges(
13883        &mut self,
13884        range: Range<usize>,
13885        reversed: bool,
13886        replace_newest: bool,
13887        auto_scroll: Option<Autoscroll>,
13888        window: &mut Window,
13889        cx: &mut Context<Editor>,
13890    ) {
13891        self.unfold_ranges(
13892            std::slice::from_ref(&range),
13893            false,
13894            auto_scroll.is_some(),
13895            cx,
13896        );
13897        let effects = if let Some(scroll) = auto_scroll {
13898            SelectionEffects::scroll(scroll)
13899        } else {
13900            SelectionEffects::no_scroll()
13901        };
13902        self.change_selections(effects, window, cx, |s| {
13903            if replace_newest {
13904                s.delete(s.newest_anchor().id);
13905            }
13906            if reversed {
13907                s.insert_range(range.end..range.start);
13908            } else {
13909                s.insert_range(range);
13910            }
13911        });
13912    }
13913
13914    pub fn select_next_match_internal(
13915        &mut self,
13916        display_map: &DisplaySnapshot,
13917        replace_newest: bool,
13918        autoscroll: Option<Autoscroll>,
13919        window: &mut Window,
13920        cx: &mut Context<Self>,
13921    ) -> Result<()> {
13922        let buffer = &display_map.buffer_snapshot;
13923        let mut selections = self.selections.all::<usize>(cx);
13924        if let Some(mut select_next_state) = self.select_next_state.take() {
13925            let query = &select_next_state.query;
13926            if !select_next_state.done {
13927                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13928                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13929                let mut next_selected_range = None;
13930
13931                let bytes_after_last_selection =
13932                    buffer.bytes_in_range(last_selection.end..buffer.len());
13933                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13934                let query_matches = query
13935                    .stream_find_iter(bytes_after_last_selection)
13936                    .map(|result| (last_selection.end, result))
13937                    .chain(
13938                        query
13939                            .stream_find_iter(bytes_before_first_selection)
13940                            .map(|result| (0, result)),
13941                    );
13942
13943                for (start_offset, query_match) in query_matches {
13944                    let query_match = query_match.unwrap(); // can only fail due to I/O
13945                    let offset_range =
13946                        start_offset + query_match.start()..start_offset + query_match.end();
13947
13948                    if !select_next_state.wordwise
13949                        || (!buffer.is_inside_word(offset_range.start, false)
13950                            && !buffer.is_inside_word(offset_range.end, false))
13951                    {
13952                        // TODO: This is n^2, because we might check all the selections
13953                        if !selections
13954                            .iter()
13955                            .any(|selection| selection.range().overlaps(&offset_range))
13956                        {
13957                            next_selected_range = Some(offset_range);
13958                            break;
13959                        }
13960                    }
13961                }
13962
13963                if let Some(next_selected_range) = next_selected_range {
13964                    self.select_match_ranges(
13965                        next_selected_range,
13966                        last_selection.reversed,
13967                        replace_newest,
13968                        autoscroll,
13969                        window,
13970                        cx,
13971                    );
13972                } else {
13973                    select_next_state.done = true;
13974                }
13975            }
13976
13977            self.select_next_state = Some(select_next_state);
13978        } else {
13979            let mut only_carets = true;
13980            let mut same_text_selected = true;
13981            let mut selected_text = None;
13982
13983            let mut selections_iter = selections.iter().peekable();
13984            while let Some(selection) = selections_iter.next() {
13985                if selection.start != selection.end {
13986                    only_carets = false;
13987                }
13988
13989                if same_text_selected {
13990                    if selected_text.is_none() {
13991                        selected_text =
13992                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13993                    }
13994
13995                    if let Some(next_selection) = selections_iter.peek() {
13996                        if next_selection.range().len() == selection.range().len() {
13997                            let next_selected_text = buffer
13998                                .text_for_range(next_selection.range())
13999                                .collect::<String>();
14000                            if Some(next_selected_text) != selected_text {
14001                                same_text_selected = false;
14002                                selected_text = None;
14003                            }
14004                        } else {
14005                            same_text_selected = false;
14006                            selected_text = None;
14007                        }
14008                    }
14009                }
14010            }
14011
14012            if only_carets {
14013                for selection in &mut selections {
14014                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14015                    selection.start = word_range.start;
14016                    selection.end = word_range.end;
14017                    selection.goal = SelectionGoal::None;
14018                    selection.reversed = false;
14019                    self.select_match_ranges(
14020                        selection.start..selection.end,
14021                        selection.reversed,
14022                        replace_newest,
14023                        autoscroll,
14024                        window,
14025                        cx,
14026                    );
14027                }
14028
14029                if selections.len() == 1 {
14030                    let selection = selections
14031                        .last()
14032                        .expect("ensured that there's only one selection");
14033                    let query = buffer
14034                        .text_for_range(selection.start..selection.end)
14035                        .collect::<String>();
14036                    let is_empty = query.is_empty();
14037                    let select_state = SelectNextState {
14038                        query: AhoCorasick::new(&[query])?,
14039                        wordwise: true,
14040                        done: is_empty,
14041                    };
14042                    self.select_next_state = Some(select_state);
14043                } else {
14044                    self.select_next_state = None;
14045                }
14046            } else if let Some(selected_text) = selected_text {
14047                self.select_next_state = Some(SelectNextState {
14048                    query: AhoCorasick::new(&[selected_text])?,
14049                    wordwise: false,
14050                    done: false,
14051                });
14052                self.select_next_match_internal(
14053                    display_map,
14054                    replace_newest,
14055                    autoscroll,
14056                    window,
14057                    cx,
14058                )?;
14059            }
14060        }
14061        Ok(())
14062    }
14063
14064    pub fn select_all_matches(
14065        &mut self,
14066        _action: &SelectAllMatches,
14067        window: &mut Window,
14068        cx: &mut Context<Self>,
14069    ) -> Result<()> {
14070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14071
14072        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14073
14074        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14075        let Some(select_next_state) = self.select_next_state.as_mut() else {
14076            return Ok(());
14077        };
14078        if select_next_state.done {
14079            return Ok(());
14080        }
14081
14082        let mut new_selections = Vec::new();
14083
14084        let reversed = self.selections.oldest::<usize>(cx).reversed;
14085        let buffer = &display_map.buffer_snapshot;
14086        let query_matches = select_next_state
14087            .query
14088            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14089
14090        for query_match in query_matches.into_iter() {
14091            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14092            let offset_range = if reversed {
14093                query_match.end()..query_match.start()
14094            } else {
14095                query_match.start()..query_match.end()
14096            };
14097
14098            if !select_next_state.wordwise
14099                || (!buffer.is_inside_word(offset_range.start, false)
14100                    && !buffer.is_inside_word(offset_range.end, false))
14101            {
14102                new_selections.push(offset_range.start..offset_range.end);
14103            }
14104        }
14105
14106        select_next_state.done = true;
14107
14108        if new_selections.is_empty() {
14109            log::error!("bug: new_selections is empty in select_all_matches");
14110            return Ok(());
14111        }
14112
14113        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14114        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14115            selections.select_ranges(new_selections)
14116        });
14117
14118        Ok(())
14119    }
14120
14121    pub fn select_next(
14122        &mut self,
14123        action: &SelectNext,
14124        window: &mut Window,
14125        cx: &mut Context<Self>,
14126    ) -> Result<()> {
14127        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14128        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14129        self.select_next_match_internal(
14130            &display_map,
14131            action.replace_newest,
14132            Some(Autoscroll::newest()),
14133            window,
14134            cx,
14135        )?;
14136        Ok(())
14137    }
14138
14139    pub fn select_previous(
14140        &mut self,
14141        action: &SelectPrevious,
14142        window: &mut Window,
14143        cx: &mut Context<Self>,
14144    ) -> Result<()> {
14145        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14146        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14147        let buffer = &display_map.buffer_snapshot;
14148        let mut selections = self.selections.all::<usize>(cx);
14149        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14150            let query = &select_prev_state.query;
14151            if !select_prev_state.done {
14152                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14153                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14154                let mut next_selected_range = None;
14155                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14156                let bytes_before_last_selection =
14157                    buffer.reversed_bytes_in_range(0..last_selection.start);
14158                let bytes_after_first_selection =
14159                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14160                let query_matches = query
14161                    .stream_find_iter(bytes_before_last_selection)
14162                    .map(|result| (last_selection.start, result))
14163                    .chain(
14164                        query
14165                            .stream_find_iter(bytes_after_first_selection)
14166                            .map(|result| (buffer.len(), result)),
14167                    );
14168                for (end_offset, query_match) in query_matches {
14169                    let query_match = query_match.unwrap(); // can only fail due to I/O
14170                    let offset_range =
14171                        end_offset - query_match.end()..end_offset - query_match.start();
14172
14173                    if !select_prev_state.wordwise
14174                        || (!buffer.is_inside_word(offset_range.start, false)
14175                            && !buffer.is_inside_word(offset_range.end, false))
14176                    {
14177                        next_selected_range = Some(offset_range);
14178                        break;
14179                    }
14180                }
14181
14182                if let Some(next_selected_range) = next_selected_range {
14183                    self.select_match_ranges(
14184                        next_selected_range,
14185                        last_selection.reversed,
14186                        action.replace_newest,
14187                        Some(Autoscroll::newest()),
14188                        window,
14189                        cx,
14190                    );
14191                } else {
14192                    select_prev_state.done = true;
14193                }
14194            }
14195
14196            self.select_prev_state = Some(select_prev_state);
14197        } else {
14198            let mut only_carets = true;
14199            let mut same_text_selected = true;
14200            let mut selected_text = None;
14201
14202            let mut selections_iter = selections.iter().peekable();
14203            while let Some(selection) = selections_iter.next() {
14204                if selection.start != selection.end {
14205                    only_carets = false;
14206                }
14207
14208                if same_text_selected {
14209                    if selected_text.is_none() {
14210                        selected_text =
14211                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14212                    }
14213
14214                    if let Some(next_selection) = selections_iter.peek() {
14215                        if next_selection.range().len() == selection.range().len() {
14216                            let next_selected_text = buffer
14217                                .text_for_range(next_selection.range())
14218                                .collect::<String>();
14219                            if Some(next_selected_text) != selected_text {
14220                                same_text_selected = false;
14221                                selected_text = None;
14222                            }
14223                        } else {
14224                            same_text_selected = false;
14225                            selected_text = None;
14226                        }
14227                    }
14228                }
14229            }
14230
14231            if only_carets {
14232                for selection in &mut selections {
14233                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14234                    selection.start = word_range.start;
14235                    selection.end = word_range.end;
14236                    selection.goal = SelectionGoal::None;
14237                    selection.reversed = false;
14238                    self.select_match_ranges(
14239                        selection.start..selection.end,
14240                        selection.reversed,
14241                        action.replace_newest,
14242                        Some(Autoscroll::newest()),
14243                        window,
14244                        cx,
14245                    );
14246                }
14247                if selections.len() == 1 {
14248                    let selection = selections
14249                        .last()
14250                        .expect("ensured that there's only one selection");
14251                    let query = buffer
14252                        .text_for_range(selection.start..selection.end)
14253                        .collect::<String>();
14254                    let is_empty = query.is_empty();
14255                    let select_state = SelectNextState {
14256                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14257                        wordwise: true,
14258                        done: is_empty,
14259                    };
14260                    self.select_prev_state = Some(select_state);
14261                } else {
14262                    self.select_prev_state = None;
14263                }
14264            } else if let Some(selected_text) = selected_text {
14265                self.select_prev_state = Some(SelectNextState {
14266                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14267                    wordwise: false,
14268                    done: false,
14269                });
14270                self.select_previous(action, window, cx)?;
14271            }
14272        }
14273        Ok(())
14274    }
14275
14276    pub fn find_next_match(
14277        &mut self,
14278        _: &FindNextMatch,
14279        window: &mut Window,
14280        cx: &mut Context<Self>,
14281    ) -> Result<()> {
14282        let selections = self.selections.disjoint_anchors();
14283        match selections.first() {
14284            Some(first) if selections.len() >= 2 => {
14285                self.change_selections(Default::default(), window, cx, |s| {
14286                    s.select_ranges([first.range()]);
14287                });
14288            }
14289            _ => self.select_next(
14290                &SelectNext {
14291                    replace_newest: true,
14292                },
14293                window,
14294                cx,
14295            )?,
14296        }
14297        Ok(())
14298    }
14299
14300    pub fn find_previous_match(
14301        &mut self,
14302        _: &FindPreviousMatch,
14303        window: &mut Window,
14304        cx: &mut Context<Self>,
14305    ) -> Result<()> {
14306        let selections = self.selections.disjoint_anchors();
14307        match selections.last() {
14308            Some(last) if selections.len() >= 2 => {
14309                self.change_selections(Default::default(), window, cx, |s| {
14310                    s.select_ranges([last.range()]);
14311                });
14312            }
14313            _ => self.select_previous(
14314                &SelectPrevious {
14315                    replace_newest: true,
14316                },
14317                window,
14318                cx,
14319            )?,
14320        }
14321        Ok(())
14322    }
14323
14324    pub fn toggle_comments(
14325        &mut self,
14326        action: &ToggleComments,
14327        window: &mut Window,
14328        cx: &mut Context<Self>,
14329    ) {
14330        if self.read_only(cx) {
14331            return;
14332        }
14333        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14334        let text_layout_details = &self.text_layout_details(window);
14335        self.transact(window, cx, |this, window, cx| {
14336            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14337            let mut edits = Vec::new();
14338            let mut selection_edit_ranges = Vec::new();
14339            let mut last_toggled_row = None;
14340            let snapshot = this.buffer.read(cx).read(cx);
14341            let empty_str: Arc<str> = Arc::default();
14342            let mut suffixes_inserted = Vec::new();
14343            let ignore_indent = action.ignore_indent;
14344
14345            fn comment_prefix_range(
14346                snapshot: &MultiBufferSnapshot,
14347                row: MultiBufferRow,
14348                comment_prefix: &str,
14349                comment_prefix_whitespace: &str,
14350                ignore_indent: bool,
14351            ) -> Range<Point> {
14352                let indent_size = if ignore_indent {
14353                    0
14354                } else {
14355                    snapshot.indent_size_for_line(row).len
14356                };
14357
14358                let start = Point::new(row.0, indent_size);
14359
14360                let mut line_bytes = snapshot
14361                    .bytes_in_range(start..snapshot.max_point())
14362                    .flatten()
14363                    .copied();
14364
14365                // If this line currently begins with the line comment prefix, then record
14366                // the range containing the prefix.
14367                if line_bytes
14368                    .by_ref()
14369                    .take(comment_prefix.len())
14370                    .eq(comment_prefix.bytes())
14371                {
14372                    // Include any whitespace that matches the comment prefix.
14373                    let matching_whitespace_len = line_bytes
14374                        .zip(comment_prefix_whitespace.bytes())
14375                        .take_while(|(a, b)| a == b)
14376                        .count() as u32;
14377                    let end = Point::new(
14378                        start.row,
14379                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14380                    );
14381                    start..end
14382                } else {
14383                    start..start
14384                }
14385            }
14386
14387            fn comment_suffix_range(
14388                snapshot: &MultiBufferSnapshot,
14389                row: MultiBufferRow,
14390                comment_suffix: &str,
14391                comment_suffix_has_leading_space: bool,
14392            ) -> Range<Point> {
14393                let end = Point::new(row.0, snapshot.line_len(row));
14394                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14395
14396                let mut line_end_bytes = snapshot
14397                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14398                    .flatten()
14399                    .copied();
14400
14401                let leading_space_len = if suffix_start_column > 0
14402                    && line_end_bytes.next() == Some(b' ')
14403                    && comment_suffix_has_leading_space
14404                {
14405                    1
14406                } else {
14407                    0
14408                };
14409
14410                // If this line currently begins with the line comment prefix, then record
14411                // the range containing the prefix.
14412                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14413                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14414                    start..end
14415                } else {
14416                    end..end
14417                }
14418            }
14419
14420            // TODO: Handle selections that cross excerpts
14421            for selection in &mut selections {
14422                let start_column = snapshot
14423                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14424                    .len;
14425                let language = if let Some(language) =
14426                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14427                {
14428                    language
14429                } else {
14430                    continue;
14431                };
14432
14433                selection_edit_ranges.clear();
14434
14435                // If multiple selections contain a given row, avoid processing that
14436                // row more than once.
14437                let mut start_row = MultiBufferRow(selection.start.row);
14438                if last_toggled_row == Some(start_row) {
14439                    start_row = start_row.next_row();
14440                }
14441                let end_row =
14442                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14443                        MultiBufferRow(selection.end.row - 1)
14444                    } else {
14445                        MultiBufferRow(selection.end.row)
14446                    };
14447                last_toggled_row = Some(end_row);
14448
14449                if start_row > end_row {
14450                    continue;
14451                }
14452
14453                // If the language has line comments, toggle those.
14454                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14455
14456                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14457                if ignore_indent {
14458                    full_comment_prefixes = full_comment_prefixes
14459                        .into_iter()
14460                        .map(|s| Arc::from(s.trim_end()))
14461                        .collect();
14462                }
14463
14464                if !full_comment_prefixes.is_empty() {
14465                    let first_prefix = full_comment_prefixes
14466                        .first()
14467                        .expect("prefixes is non-empty");
14468                    let prefix_trimmed_lengths = full_comment_prefixes
14469                        .iter()
14470                        .map(|p| p.trim_end_matches(' ').len())
14471                        .collect::<SmallVec<[usize; 4]>>();
14472
14473                    let mut all_selection_lines_are_comments = true;
14474
14475                    for row in start_row.0..=end_row.0 {
14476                        let row = MultiBufferRow(row);
14477                        if start_row < end_row && snapshot.is_line_blank(row) {
14478                            continue;
14479                        }
14480
14481                        let prefix_range = full_comment_prefixes
14482                            .iter()
14483                            .zip(prefix_trimmed_lengths.iter().copied())
14484                            .map(|(prefix, trimmed_prefix_len)| {
14485                                comment_prefix_range(
14486                                    snapshot.deref(),
14487                                    row,
14488                                    &prefix[..trimmed_prefix_len],
14489                                    &prefix[trimmed_prefix_len..],
14490                                    ignore_indent,
14491                                )
14492                            })
14493                            .max_by_key(|range| range.end.column - range.start.column)
14494                            .expect("prefixes is non-empty");
14495
14496                        if prefix_range.is_empty() {
14497                            all_selection_lines_are_comments = false;
14498                        }
14499
14500                        selection_edit_ranges.push(prefix_range);
14501                    }
14502
14503                    if all_selection_lines_are_comments {
14504                        edits.extend(
14505                            selection_edit_ranges
14506                                .iter()
14507                                .cloned()
14508                                .map(|range| (range, empty_str.clone())),
14509                        );
14510                    } else {
14511                        let min_column = selection_edit_ranges
14512                            .iter()
14513                            .map(|range| range.start.column)
14514                            .min()
14515                            .unwrap_or(0);
14516                        edits.extend(selection_edit_ranges.iter().map(|range| {
14517                            let position = Point::new(range.start.row, min_column);
14518                            (position..position, first_prefix.clone())
14519                        }));
14520                    }
14521                } else if let Some(BlockCommentConfig {
14522                    start: full_comment_prefix,
14523                    end: comment_suffix,
14524                    ..
14525                }) = language.block_comment()
14526                {
14527                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14528                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14529                    let prefix_range = comment_prefix_range(
14530                        snapshot.deref(),
14531                        start_row,
14532                        comment_prefix,
14533                        comment_prefix_whitespace,
14534                        ignore_indent,
14535                    );
14536                    let suffix_range = comment_suffix_range(
14537                        snapshot.deref(),
14538                        end_row,
14539                        comment_suffix.trim_start_matches(' '),
14540                        comment_suffix.starts_with(' '),
14541                    );
14542
14543                    if prefix_range.is_empty() || suffix_range.is_empty() {
14544                        edits.push((
14545                            prefix_range.start..prefix_range.start,
14546                            full_comment_prefix.clone(),
14547                        ));
14548                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14549                        suffixes_inserted.push((end_row, comment_suffix.len()));
14550                    } else {
14551                        edits.push((prefix_range, empty_str.clone()));
14552                        edits.push((suffix_range, empty_str.clone()));
14553                    }
14554                } else {
14555                    continue;
14556                }
14557            }
14558
14559            drop(snapshot);
14560            this.buffer.update(cx, |buffer, cx| {
14561                buffer.edit(edits, None, cx);
14562            });
14563
14564            // Adjust selections so that they end before any comment suffixes that
14565            // were inserted.
14566            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14567            let mut selections = this.selections.all::<Point>(cx);
14568            let snapshot = this.buffer.read(cx).read(cx);
14569            for selection in &mut selections {
14570                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14571                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14572                        Ordering::Less => {
14573                            suffixes_inserted.next();
14574                            continue;
14575                        }
14576                        Ordering::Greater => break,
14577                        Ordering::Equal => {
14578                            if selection.end.column == snapshot.line_len(row) {
14579                                if selection.is_empty() {
14580                                    selection.start.column -= suffix_len as u32;
14581                                }
14582                                selection.end.column -= suffix_len as u32;
14583                            }
14584                            break;
14585                        }
14586                    }
14587                }
14588            }
14589
14590            drop(snapshot);
14591            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14592
14593            let selections = this.selections.all::<Point>(cx);
14594            let selections_on_single_row = selections.windows(2).all(|selections| {
14595                selections[0].start.row == selections[1].start.row
14596                    && selections[0].end.row == selections[1].end.row
14597                    && selections[0].start.row == selections[0].end.row
14598            });
14599            let selections_selecting = selections
14600                .iter()
14601                .any(|selection| selection.start != selection.end);
14602            let advance_downwards = action.advance_downwards
14603                && selections_on_single_row
14604                && !selections_selecting
14605                && !matches!(this.mode, EditorMode::SingleLine { .. });
14606
14607            if advance_downwards {
14608                let snapshot = this.buffer.read(cx).snapshot(cx);
14609
14610                this.change_selections(Default::default(), window, cx, |s| {
14611                    s.move_cursors_with(|display_snapshot, display_point, _| {
14612                        let mut point = display_point.to_point(display_snapshot);
14613                        point.row += 1;
14614                        point = snapshot.clip_point(point, Bias::Left);
14615                        let display_point = point.to_display_point(display_snapshot);
14616                        let goal = SelectionGoal::HorizontalPosition(
14617                            display_snapshot
14618                                .x_for_display_point(display_point, text_layout_details)
14619                                .into(),
14620                        );
14621                        (display_point, goal)
14622                    })
14623                });
14624            }
14625        });
14626    }
14627
14628    pub fn select_enclosing_symbol(
14629        &mut self,
14630        _: &SelectEnclosingSymbol,
14631        window: &mut Window,
14632        cx: &mut Context<Self>,
14633    ) {
14634        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14635
14636        let buffer = self.buffer.read(cx).snapshot(cx);
14637        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14638
14639        fn update_selection(
14640            selection: &Selection<usize>,
14641            buffer_snap: &MultiBufferSnapshot,
14642        ) -> Option<Selection<usize>> {
14643            let cursor = selection.head();
14644            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14645            for symbol in symbols.iter().rev() {
14646                let start = symbol.range.start.to_offset(buffer_snap);
14647                let end = symbol.range.end.to_offset(buffer_snap);
14648                let new_range = start..end;
14649                if start < selection.start || end > selection.end {
14650                    return Some(Selection {
14651                        id: selection.id,
14652                        start: new_range.start,
14653                        end: new_range.end,
14654                        goal: SelectionGoal::None,
14655                        reversed: selection.reversed,
14656                    });
14657                }
14658            }
14659            None
14660        }
14661
14662        let mut selected_larger_symbol = false;
14663        let new_selections = old_selections
14664            .iter()
14665            .map(|selection| match update_selection(selection, &buffer) {
14666                Some(new_selection) => {
14667                    if new_selection.range() != selection.range() {
14668                        selected_larger_symbol = true;
14669                    }
14670                    new_selection
14671                }
14672                None => selection.clone(),
14673            })
14674            .collect::<Vec<_>>();
14675
14676        if selected_larger_symbol {
14677            self.change_selections(Default::default(), window, cx, |s| {
14678                s.select(new_selections);
14679            });
14680        }
14681    }
14682
14683    pub fn select_larger_syntax_node(
14684        &mut self,
14685        _: &SelectLargerSyntaxNode,
14686        window: &mut Window,
14687        cx: &mut Context<Self>,
14688    ) {
14689        let Some(visible_row_count) = self.visible_row_count() else {
14690            return;
14691        };
14692        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14693        if old_selections.is_empty() {
14694            return;
14695        }
14696
14697        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14698
14699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14700        let buffer = self.buffer.read(cx).snapshot(cx);
14701
14702        let mut selected_larger_node = false;
14703        let mut new_selections = old_selections
14704            .iter()
14705            .map(|selection| {
14706                let old_range = selection.start..selection.end;
14707
14708                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14709                    // manually select word at selection
14710                    if ["string_content", "inline"].contains(&node.kind()) {
14711                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14712                        // ignore if word is already selected
14713                        if !word_range.is_empty() && old_range != word_range {
14714                            let (last_word_range, _) =
14715                                buffer.surrounding_word(old_range.end, false);
14716                            // only select word if start and end point belongs to same word
14717                            if word_range == last_word_range {
14718                                selected_larger_node = true;
14719                                return Selection {
14720                                    id: selection.id,
14721                                    start: word_range.start,
14722                                    end: word_range.end,
14723                                    goal: SelectionGoal::None,
14724                                    reversed: selection.reversed,
14725                                };
14726                            }
14727                        }
14728                    }
14729                }
14730
14731                let mut new_range = old_range.clone();
14732                while let Some((_node, containing_range)) =
14733                    buffer.syntax_ancestor(new_range.clone())
14734                {
14735                    new_range = match containing_range {
14736                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14737                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14738                    };
14739                    if !display_map.intersects_fold(new_range.start)
14740                        && !display_map.intersects_fold(new_range.end)
14741                    {
14742                        break;
14743                    }
14744                }
14745
14746                selected_larger_node |= new_range != old_range;
14747                Selection {
14748                    id: selection.id,
14749                    start: new_range.start,
14750                    end: new_range.end,
14751                    goal: SelectionGoal::None,
14752                    reversed: selection.reversed,
14753                }
14754            })
14755            .collect::<Vec<_>>();
14756
14757        if !selected_larger_node {
14758            return; // don't put this call in the history
14759        }
14760
14761        // scroll based on transformation done to the last selection created by the user
14762        let (last_old, last_new) = old_selections
14763            .last()
14764            .zip(new_selections.last().cloned())
14765            .expect("old_selections isn't empty");
14766
14767        // revert selection
14768        let is_selection_reversed = {
14769            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14770            new_selections.last_mut().expect("checked above").reversed =
14771                should_newest_selection_be_reversed;
14772            should_newest_selection_be_reversed
14773        };
14774
14775        if selected_larger_node {
14776            self.select_syntax_node_history.disable_clearing = true;
14777            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14778                s.select(new_selections.clone());
14779            });
14780            self.select_syntax_node_history.disable_clearing = false;
14781        }
14782
14783        let start_row = last_new.start.to_display_point(&display_map).row().0;
14784        let end_row = last_new.end.to_display_point(&display_map).row().0;
14785        let selection_height = end_row - start_row + 1;
14786        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14787
14788        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14789        let scroll_behavior = if fits_on_the_screen {
14790            self.request_autoscroll(Autoscroll::fit(), cx);
14791            SelectSyntaxNodeScrollBehavior::FitSelection
14792        } else if is_selection_reversed {
14793            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14794            SelectSyntaxNodeScrollBehavior::CursorTop
14795        } else {
14796            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14797            SelectSyntaxNodeScrollBehavior::CursorBottom
14798        };
14799
14800        self.select_syntax_node_history.push((
14801            old_selections,
14802            scroll_behavior,
14803            is_selection_reversed,
14804        ));
14805    }
14806
14807    pub fn select_smaller_syntax_node(
14808        &mut self,
14809        _: &SelectSmallerSyntaxNode,
14810        window: &mut Window,
14811        cx: &mut Context<Self>,
14812    ) {
14813        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14814
14815        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14816            self.select_syntax_node_history.pop()
14817        {
14818            if let Some(selection) = selections.last_mut() {
14819                selection.reversed = is_selection_reversed;
14820            }
14821
14822            self.select_syntax_node_history.disable_clearing = true;
14823            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14824                s.select(selections.to_vec());
14825            });
14826            self.select_syntax_node_history.disable_clearing = false;
14827
14828            match scroll_behavior {
14829                SelectSyntaxNodeScrollBehavior::CursorTop => {
14830                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14831                }
14832                SelectSyntaxNodeScrollBehavior::FitSelection => {
14833                    self.request_autoscroll(Autoscroll::fit(), cx);
14834                }
14835                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14836                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14837                }
14838            }
14839        }
14840    }
14841
14842    pub fn unwrap_syntax_node(
14843        &mut self,
14844        _: &UnwrapSyntaxNode,
14845        window: &mut Window,
14846        cx: &mut Context<Self>,
14847    ) {
14848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14849
14850        let buffer = self.buffer.read(cx).snapshot(cx);
14851        let selections = self
14852            .selections
14853            .all::<usize>(cx)
14854            .into_iter()
14855            // subtracting the offset requires sorting
14856            .sorted_by_key(|i| i.start);
14857
14858        let full_edits = selections
14859            .into_iter()
14860            .filter_map(|selection| {
14861                // Only requires two branches once if-let-chains stabilize (#53667)
14862                let child = if !selection.is_empty() {
14863                    selection.range()
14864                } else if let Some((_, ancestor_range)) =
14865                    buffer.syntax_ancestor(selection.start..selection.end)
14866                {
14867                    match ancestor_range {
14868                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14869                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14870                    }
14871                } else {
14872                    selection.range()
14873                };
14874
14875                let mut parent = child.clone();
14876                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14877                    parent = match ancestor_range {
14878                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14879                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14880                    };
14881                    if parent.start < child.start || parent.end > child.end {
14882                        break;
14883                    }
14884                }
14885
14886                if parent == child {
14887                    return None;
14888                }
14889                let text = buffer.text_for_range(child.clone()).collect::<String>();
14890                Some((selection.id, parent, text))
14891            })
14892            .collect::<Vec<_>>();
14893
14894        self.transact(window, cx, |this, window, cx| {
14895            this.buffer.update(cx, |buffer, cx| {
14896                buffer.edit(
14897                    full_edits
14898                        .iter()
14899                        .map(|(_, p, t)| (p.clone(), t.clone()))
14900                        .collect::<Vec<_>>(),
14901                    None,
14902                    cx,
14903                );
14904            });
14905            this.change_selections(Default::default(), window, cx, |s| {
14906                let mut offset = 0;
14907                let mut selections = vec![];
14908                for (id, parent, text) in full_edits {
14909                    let start = parent.start - offset;
14910                    offset += parent.len() - text.len();
14911                    selections.push(Selection {
14912                        id: id,
14913                        start,
14914                        end: start + text.len(),
14915                        reversed: false,
14916                        goal: Default::default(),
14917                    });
14918                }
14919                s.select(selections);
14920            });
14921        });
14922    }
14923
14924    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14925        if !EditorSettings::get_global(cx).gutter.runnables {
14926            self.clear_tasks();
14927            return Task::ready(());
14928        }
14929        let project = self.project().map(Entity::downgrade);
14930        let task_sources = self.lsp_task_sources(cx);
14931        let multi_buffer = self.buffer.downgrade();
14932        cx.spawn_in(window, async move |editor, cx| {
14933            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14934            let Some(project) = project.and_then(|p| p.upgrade()) else {
14935                return;
14936            };
14937            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14938                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14939            }) else {
14940                return;
14941            };
14942
14943            let hide_runnables = project
14944                .update(cx, |project, cx| {
14945                    // Do not display any test indicators in non-dev server remote projects.
14946                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14947                })
14948                .unwrap_or(true);
14949            if hide_runnables {
14950                return;
14951            }
14952            let new_rows =
14953                cx.background_spawn({
14954                    let snapshot = display_snapshot.clone();
14955                    async move {
14956                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14957                    }
14958                })
14959                    .await;
14960            let Ok(lsp_tasks) =
14961                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14962            else {
14963                return;
14964            };
14965            let lsp_tasks = lsp_tasks.await;
14966
14967            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14968                lsp_tasks
14969                    .into_iter()
14970                    .flat_map(|(kind, tasks)| {
14971                        tasks.into_iter().filter_map(move |(location, task)| {
14972                            Some((kind.clone(), location?, task))
14973                        })
14974                    })
14975                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14976                        let buffer = location.target.buffer;
14977                        let buffer_snapshot = buffer.read(cx).snapshot();
14978                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14979                            |(excerpt_id, snapshot, _)| {
14980                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14981                                    display_snapshot
14982                                        .buffer_snapshot
14983                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14984                                } else {
14985                                    None
14986                                }
14987                            },
14988                        );
14989                        if let Some(offset) = offset {
14990                            let task_buffer_range =
14991                                location.target.range.to_point(&buffer_snapshot);
14992                            let context_buffer_range =
14993                                task_buffer_range.to_offset(&buffer_snapshot);
14994                            let context_range = BufferOffset(context_buffer_range.start)
14995                                ..BufferOffset(context_buffer_range.end);
14996
14997                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14998                                .or_insert_with(|| RunnableTasks {
14999                                    templates: Vec::new(),
15000                                    offset,
15001                                    column: task_buffer_range.start.column,
15002                                    extra_variables: HashMap::default(),
15003                                    context_range,
15004                                })
15005                                .templates
15006                                .push((kind, task.original_task().clone()));
15007                        }
15008
15009                        acc
15010                    })
15011            }) else {
15012                return;
15013            };
15014
15015            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15016                buffer.language_settings(cx).tasks.prefer_lsp
15017            }) else {
15018                return;
15019            };
15020
15021            let rows = Self::runnable_rows(
15022                project,
15023                display_snapshot,
15024                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15025                new_rows,
15026                cx.clone(),
15027            )
15028            .await;
15029            editor
15030                .update(cx, |editor, _| {
15031                    editor.clear_tasks();
15032                    for (key, mut value) in rows {
15033                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15034                            value.templates.extend(lsp_tasks.templates);
15035                        }
15036
15037                        editor.insert_tasks(key, value);
15038                    }
15039                    for (key, value) in lsp_tasks_by_rows {
15040                        editor.insert_tasks(key, value);
15041                    }
15042                })
15043                .ok();
15044        })
15045    }
15046    fn fetch_runnable_ranges(
15047        snapshot: &DisplaySnapshot,
15048        range: Range<Anchor>,
15049    ) -> Vec<language::RunnableRange> {
15050        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15051    }
15052
15053    fn runnable_rows(
15054        project: Entity<Project>,
15055        snapshot: DisplaySnapshot,
15056        prefer_lsp: bool,
15057        runnable_ranges: Vec<RunnableRange>,
15058        cx: AsyncWindowContext,
15059    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15060        cx.spawn(async move |cx| {
15061            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15062            for mut runnable in runnable_ranges {
15063                let Some(tasks) = cx
15064                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15065                    .ok()
15066                else {
15067                    continue;
15068                };
15069                let mut tasks = tasks.await;
15070
15071                if prefer_lsp {
15072                    tasks.retain(|(task_kind, _)| {
15073                        !matches!(task_kind, TaskSourceKind::Language { .. })
15074                    });
15075                }
15076                if tasks.is_empty() {
15077                    continue;
15078                }
15079
15080                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15081                let Some(row) = snapshot
15082                    .buffer_snapshot
15083                    .buffer_line_for_row(MultiBufferRow(point.row))
15084                    .map(|(_, range)| range.start.row)
15085                else {
15086                    continue;
15087                };
15088
15089                let context_range =
15090                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15091                runnable_rows.push((
15092                    (runnable.buffer_id, row),
15093                    RunnableTasks {
15094                        templates: tasks,
15095                        offset: snapshot
15096                            .buffer_snapshot
15097                            .anchor_before(runnable.run_range.start),
15098                        context_range,
15099                        column: point.column,
15100                        extra_variables: runnable.extra_captures,
15101                    },
15102                ));
15103            }
15104            runnable_rows
15105        })
15106    }
15107
15108    fn templates_with_tags(
15109        project: &Entity<Project>,
15110        runnable: &mut Runnable,
15111        cx: &mut App,
15112    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15113        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15114            let (worktree_id, file) = project
15115                .buffer_for_id(runnable.buffer, cx)
15116                .and_then(|buffer| buffer.read(cx).file())
15117                .map(|file| (file.worktree_id(cx), file.clone()))
15118                .unzip();
15119
15120            (
15121                project.task_store().read(cx).task_inventory().cloned(),
15122                worktree_id,
15123                file,
15124            )
15125        });
15126
15127        let tags = mem::take(&mut runnable.tags);
15128        let language = runnable.language.clone();
15129        cx.spawn(async move |cx| {
15130            let mut templates_with_tags = Vec::new();
15131            if let Some(inventory) = inventory {
15132                for RunnableTag(tag) in tags {
15133                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15134                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15135                    }) else {
15136                        return templates_with_tags;
15137                    };
15138                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15139                        move |(_, template)| {
15140                            template.tags.iter().any(|source_tag| source_tag == &tag)
15141                        },
15142                    ));
15143                }
15144            }
15145            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15146
15147            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15148                // Strongest source wins; if we have worktree tag binding, prefer that to
15149                // global and language bindings;
15150                // if we have a global binding, prefer that to language binding.
15151                let first_mismatch = templates_with_tags
15152                    .iter()
15153                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15154                if let Some(index) = first_mismatch {
15155                    templates_with_tags.truncate(index);
15156                }
15157            }
15158
15159            templates_with_tags
15160        })
15161    }
15162
15163    pub fn move_to_enclosing_bracket(
15164        &mut self,
15165        _: &MoveToEnclosingBracket,
15166        window: &mut Window,
15167        cx: &mut Context<Self>,
15168    ) {
15169        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15170        self.change_selections(Default::default(), window, cx, |s| {
15171            s.move_offsets_with(|snapshot, selection| {
15172                let Some(enclosing_bracket_ranges) =
15173                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15174                else {
15175                    return;
15176                };
15177
15178                let mut best_length = usize::MAX;
15179                let mut best_inside = false;
15180                let mut best_in_bracket_range = false;
15181                let mut best_destination = None;
15182                for (open, close) in enclosing_bracket_ranges {
15183                    let close = close.to_inclusive();
15184                    let length = close.end() - open.start;
15185                    let inside = selection.start >= open.end && selection.end <= *close.start();
15186                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15187                        || close.contains(&selection.head());
15188
15189                    // If best is next to a bracket and current isn't, skip
15190                    if !in_bracket_range && best_in_bracket_range {
15191                        continue;
15192                    }
15193
15194                    // Prefer smaller lengths unless best is inside and current isn't
15195                    if length > best_length && (best_inside || !inside) {
15196                        continue;
15197                    }
15198
15199                    best_length = length;
15200                    best_inside = inside;
15201                    best_in_bracket_range = in_bracket_range;
15202                    best_destination = Some(
15203                        if close.contains(&selection.start) && close.contains(&selection.end) {
15204                            if inside { open.end } else { open.start }
15205                        } else if inside {
15206                            *close.start()
15207                        } else {
15208                            *close.end()
15209                        },
15210                    );
15211                }
15212
15213                if let Some(destination) = best_destination {
15214                    selection.collapse_to(destination, SelectionGoal::None);
15215                }
15216            })
15217        });
15218    }
15219
15220    pub fn undo_selection(
15221        &mut self,
15222        _: &UndoSelection,
15223        window: &mut Window,
15224        cx: &mut Context<Self>,
15225    ) {
15226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15227        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15228            self.selection_history.mode = SelectionHistoryMode::Undoing;
15229            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15230                this.end_selection(window, cx);
15231                this.change_selections(
15232                    SelectionEffects::scroll(Autoscroll::newest()),
15233                    window,
15234                    cx,
15235                    |s| s.select_anchors(entry.selections.to_vec()),
15236                );
15237            });
15238            self.selection_history.mode = SelectionHistoryMode::Normal;
15239
15240            self.select_next_state = entry.select_next_state;
15241            self.select_prev_state = entry.select_prev_state;
15242            self.add_selections_state = entry.add_selections_state;
15243        }
15244    }
15245
15246    pub fn redo_selection(
15247        &mut self,
15248        _: &RedoSelection,
15249        window: &mut Window,
15250        cx: &mut Context<Self>,
15251    ) {
15252        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15253        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15254            self.selection_history.mode = SelectionHistoryMode::Redoing;
15255            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15256                this.end_selection(window, cx);
15257                this.change_selections(
15258                    SelectionEffects::scroll(Autoscroll::newest()),
15259                    window,
15260                    cx,
15261                    |s| s.select_anchors(entry.selections.to_vec()),
15262                );
15263            });
15264            self.selection_history.mode = SelectionHistoryMode::Normal;
15265
15266            self.select_next_state = entry.select_next_state;
15267            self.select_prev_state = entry.select_prev_state;
15268            self.add_selections_state = entry.add_selections_state;
15269        }
15270    }
15271
15272    pub fn expand_excerpts(
15273        &mut self,
15274        action: &ExpandExcerpts,
15275        _: &mut Window,
15276        cx: &mut Context<Self>,
15277    ) {
15278        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15279    }
15280
15281    pub fn expand_excerpts_down(
15282        &mut self,
15283        action: &ExpandExcerptsDown,
15284        _: &mut Window,
15285        cx: &mut Context<Self>,
15286    ) {
15287        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15288    }
15289
15290    pub fn expand_excerpts_up(
15291        &mut self,
15292        action: &ExpandExcerptsUp,
15293        _: &mut Window,
15294        cx: &mut Context<Self>,
15295    ) {
15296        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15297    }
15298
15299    pub fn expand_excerpts_for_direction(
15300        &mut self,
15301        lines: u32,
15302        direction: ExpandExcerptDirection,
15303
15304        cx: &mut Context<Self>,
15305    ) {
15306        let selections = self.selections.disjoint_anchors();
15307
15308        let lines = if lines == 0 {
15309            EditorSettings::get_global(cx).expand_excerpt_lines
15310        } else {
15311            lines
15312        };
15313
15314        self.buffer.update(cx, |buffer, cx| {
15315            let snapshot = buffer.snapshot(cx);
15316            let mut excerpt_ids = selections
15317                .iter()
15318                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15319                .collect::<Vec<_>>();
15320            excerpt_ids.sort();
15321            excerpt_ids.dedup();
15322            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15323        })
15324    }
15325
15326    pub fn expand_excerpt(
15327        &mut self,
15328        excerpt: ExcerptId,
15329        direction: ExpandExcerptDirection,
15330        window: &mut Window,
15331        cx: &mut Context<Self>,
15332    ) {
15333        let current_scroll_position = self.scroll_position(cx);
15334        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15335        let mut should_scroll_up = false;
15336
15337        if direction == ExpandExcerptDirection::Down {
15338            let multi_buffer = self.buffer.read(cx);
15339            let snapshot = multi_buffer.snapshot(cx);
15340            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15341                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15342                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15343            {
15344                let buffer_snapshot = buffer.read(cx).snapshot();
15345                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15346                let last_row = buffer_snapshot.max_point().row;
15347                let lines_below = last_row.saturating_sub(excerpt_end_row);
15348                should_scroll_up = lines_below >= lines_to_expand;
15349            }
15350        }
15351
15352        self.buffer.update(cx, |buffer, cx| {
15353            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15354        });
15355
15356        if should_scroll_up {
15357            let new_scroll_position =
15358                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15359            self.set_scroll_position(new_scroll_position, window, cx);
15360        }
15361    }
15362
15363    pub fn go_to_singleton_buffer_point(
15364        &mut self,
15365        point: Point,
15366        window: &mut Window,
15367        cx: &mut Context<Self>,
15368    ) {
15369        self.go_to_singleton_buffer_range(point..point, window, cx);
15370    }
15371
15372    pub fn go_to_singleton_buffer_range(
15373        &mut self,
15374        range: Range<Point>,
15375        window: &mut Window,
15376        cx: &mut Context<Self>,
15377    ) {
15378        let multibuffer = self.buffer().read(cx);
15379        let Some(buffer) = multibuffer.as_singleton() else {
15380            return;
15381        };
15382        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15383            return;
15384        };
15385        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15386            return;
15387        };
15388        self.change_selections(
15389            SelectionEffects::default().nav_history(true),
15390            window,
15391            cx,
15392            |s| s.select_anchor_ranges([start..end]),
15393        );
15394    }
15395
15396    pub fn go_to_diagnostic(
15397        &mut self,
15398        action: &GoToDiagnostic,
15399        window: &mut Window,
15400        cx: &mut Context<Self>,
15401    ) {
15402        if !self.diagnostics_enabled() {
15403            return;
15404        }
15405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15406        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15407    }
15408
15409    pub fn go_to_prev_diagnostic(
15410        &mut self,
15411        action: &GoToPreviousDiagnostic,
15412        window: &mut Window,
15413        cx: &mut Context<Self>,
15414    ) {
15415        if !self.diagnostics_enabled() {
15416            return;
15417        }
15418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15419        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15420    }
15421
15422    pub fn go_to_diagnostic_impl(
15423        &mut self,
15424        direction: Direction,
15425        severity: GoToDiagnosticSeverityFilter,
15426        window: &mut Window,
15427        cx: &mut Context<Self>,
15428    ) {
15429        let buffer = self.buffer.read(cx).snapshot(cx);
15430        let selection = self.selections.newest::<usize>(cx);
15431
15432        let mut active_group_id = None;
15433        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15434            && active_group.active_range.start.to_offset(&buffer) == selection.start
15435        {
15436            active_group_id = Some(active_group.group_id);
15437        }
15438
15439        fn filtered(
15440            snapshot: EditorSnapshot,
15441            severity: GoToDiagnosticSeverityFilter,
15442            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15443        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15444            diagnostics
15445                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15446                .filter(|entry| entry.range.start != entry.range.end)
15447                .filter(|entry| !entry.diagnostic.is_unnecessary)
15448                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15449        }
15450
15451        let snapshot = self.snapshot(window, cx);
15452        let before = filtered(
15453            snapshot.clone(),
15454            severity,
15455            buffer
15456                .diagnostics_in_range(0..selection.start)
15457                .filter(|entry| entry.range.start <= selection.start),
15458        );
15459        let after = filtered(
15460            snapshot,
15461            severity,
15462            buffer
15463                .diagnostics_in_range(selection.start..buffer.len())
15464                .filter(|entry| entry.range.start >= selection.start),
15465        );
15466
15467        let mut found: Option<DiagnosticEntry<usize>> = None;
15468        if direction == Direction::Prev {
15469            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15470            {
15471                for diagnostic in prev_diagnostics.into_iter().rev() {
15472                    if diagnostic.range.start != selection.start
15473                        || active_group_id
15474                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15475                    {
15476                        found = Some(diagnostic);
15477                        break 'outer;
15478                    }
15479                }
15480            }
15481        } else {
15482            for diagnostic in after.chain(before) {
15483                if diagnostic.range.start != selection.start
15484                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15485                {
15486                    found = Some(diagnostic);
15487                    break;
15488                }
15489            }
15490        }
15491        let Some(next_diagnostic) = found else {
15492            return;
15493        };
15494
15495        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15496            return;
15497        };
15498        self.change_selections(Default::default(), window, cx, |s| {
15499            s.select_ranges(vec![
15500                next_diagnostic.range.start..next_diagnostic.range.start,
15501            ])
15502        });
15503        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15504        self.refresh_edit_prediction(false, true, window, cx);
15505    }
15506
15507    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15508        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15509        let snapshot = self.snapshot(window, cx);
15510        let selection = self.selections.newest::<Point>(cx);
15511        self.go_to_hunk_before_or_after_position(
15512            &snapshot,
15513            selection.head(),
15514            Direction::Next,
15515            window,
15516            cx,
15517        );
15518    }
15519
15520    pub fn go_to_hunk_before_or_after_position(
15521        &mut self,
15522        snapshot: &EditorSnapshot,
15523        position: Point,
15524        direction: Direction,
15525        window: &mut Window,
15526        cx: &mut Context<Editor>,
15527    ) {
15528        let row = if direction == Direction::Next {
15529            self.hunk_after_position(snapshot, position)
15530                .map(|hunk| hunk.row_range.start)
15531        } else {
15532            self.hunk_before_position(snapshot, position)
15533        };
15534
15535        if let Some(row) = row {
15536            let destination = Point::new(row.0, 0);
15537            let autoscroll = Autoscroll::center();
15538
15539            self.unfold_ranges(&[destination..destination], false, false, cx);
15540            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15541                s.select_ranges([destination..destination]);
15542            });
15543        }
15544    }
15545
15546    fn hunk_after_position(
15547        &mut self,
15548        snapshot: &EditorSnapshot,
15549        position: Point,
15550    ) -> Option<MultiBufferDiffHunk> {
15551        snapshot
15552            .buffer_snapshot
15553            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15554            .find(|hunk| hunk.row_range.start.0 > position.row)
15555            .or_else(|| {
15556                snapshot
15557                    .buffer_snapshot
15558                    .diff_hunks_in_range(Point::zero()..position)
15559                    .find(|hunk| hunk.row_range.end.0 < position.row)
15560            })
15561    }
15562
15563    fn go_to_prev_hunk(
15564        &mut self,
15565        _: &GoToPreviousHunk,
15566        window: &mut Window,
15567        cx: &mut Context<Self>,
15568    ) {
15569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15570        let snapshot = self.snapshot(window, cx);
15571        let selection = self.selections.newest::<Point>(cx);
15572        self.go_to_hunk_before_or_after_position(
15573            &snapshot,
15574            selection.head(),
15575            Direction::Prev,
15576            window,
15577            cx,
15578        );
15579    }
15580
15581    fn hunk_before_position(
15582        &mut self,
15583        snapshot: &EditorSnapshot,
15584        position: Point,
15585    ) -> Option<MultiBufferRow> {
15586        snapshot
15587            .buffer_snapshot
15588            .diff_hunk_before(position)
15589            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15590    }
15591
15592    fn go_to_next_change(
15593        &mut self,
15594        _: &GoToNextChange,
15595        window: &mut Window,
15596        cx: &mut Context<Self>,
15597    ) {
15598        if let Some(selections) = self
15599            .change_list
15600            .next_change(1, Direction::Next)
15601            .map(|s| s.to_vec())
15602        {
15603            self.change_selections(Default::default(), window, cx, |s| {
15604                let map = s.display_map();
15605                s.select_display_ranges(selections.iter().map(|a| {
15606                    let point = a.to_display_point(&map);
15607                    point..point
15608                }))
15609            })
15610        }
15611    }
15612
15613    fn go_to_previous_change(
15614        &mut self,
15615        _: &GoToPreviousChange,
15616        window: &mut Window,
15617        cx: &mut Context<Self>,
15618    ) {
15619        if let Some(selections) = self
15620            .change_list
15621            .next_change(1, Direction::Prev)
15622            .map(|s| s.to_vec())
15623        {
15624            self.change_selections(Default::default(), window, cx, |s| {
15625                let map = s.display_map();
15626                s.select_display_ranges(selections.iter().map(|a| {
15627                    let point = a.to_display_point(&map);
15628                    point..point
15629                }))
15630            })
15631        }
15632    }
15633
15634    fn go_to_line<T: 'static>(
15635        &mut self,
15636        position: Anchor,
15637        highlight_color: Option<Hsla>,
15638        window: &mut Window,
15639        cx: &mut Context<Self>,
15640    ) {
15641        let snapshot = self.snapshot(window, cx).display_snapshot;
15642        let position = position.to_point(&snapshot.buffer_snapshot);
15643        let start = snapshot
15644            .buffer_snapshot
15645            .clip_point(Point::new(position.row, 0), Bias::Left);
15646        let end = start + Point::new(1, 0);
15647        let start = snapshot.buffer_snapshot.anchor_before(start);
15648        let end = snapshot.buffer_snapshot.anchor_before(end);
15649
15650        self.highlight_rows::<T>(
15651            start..end,
15652            highlight_color
15653                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15654            Default::default(),
15655            cx,
15656        );
15657
15658        if self.buffer.read(cx).is_singleton() {
15659            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15660        }
15661    }
15662
15663    pub fn go_to_definition(
15664        &mut self,
15665        _: &GoToDefinition,
15666        window: &mut Window,
15667        cx: &mut Context<Self>,
15668    ) -> Task<Result<Navigated>> {
15669        let definition =
15670            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15671        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15672        cx.spawn_in(window, async move |editor, cx| {
15673            if definition.await? == Navigated::Yes {
15674                return Ok(Navigated::Yes);
15675            }
15676            match fallback_strategy {
15677                GoToDefinitionFallback::None => Ok(Navigated::No),
15678                GoToDefinitionFallback::FindAllReferences => {
15679                    match editor.update_in(cx, |editor, window, cx| {
15680                        editor.find_all_references(&FindAllReferences, window, cx)
15681                    })? {
15682                        Some(references) => references.await,
15683                        None => Ok(Navigated::No),
15684                    }
15685                }
15686            }
15687        })
15688    }
15689
15690    pub fn go_to_declaration(
15691        &mut self,
15692        _: &GoToDeclaration,
15693        window: &mut Window,
15694        cx: &mut Context<Self>,
15695    ) -> Task<Result<Navigated>> {
15696        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15697    }
15698
15699    pub fn go_to_declaration_split(
15700        &mut self,
15701        _: &GoToDeclaration,
15702        window: &mut Window,
15703        cx: &mut Context<Self>,
15704    ) -> Task<Result<Navigated>> {
15705        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15706    }
15707
15708    pub fn go_to_implementation(
15709        &mut self,
15710        _: &GoToImplementation,
15711        window: &mut Window,
15712        cx: &mut Context<Self>,
15713    ) -> Task<Result<Navigated>> {
15714        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15715    }
15716
15717    pub fn go_to_implementation_split(
15718        &mut self,
15719        _: &GoToImplementationSplit,
15720        window: &mut Window,
15721        cx: &mut Context<Self>,
15722    ) -> Task<Result<Navigated>> {
15723        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15724    }
15725
15726    pub fn go_to_type_definition(
15727        &mut self,
15728        _: &GoToTypeDefinition,
15729        window: &mut Window,
15730        cx: &mut Context<Self>,
15731    ) -> Task<Result<Navigated>> {
15732        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15733    }
15734
15735    pub fn go_to_definition_split(
15736        &mut self,
15737        _: &GoToDefinitionSplit,
15738        window: &mut Window,
15739        cx: &mut Context<Self>,
15740    ) -> Task<Result<Navigated>> {
15741        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15742    }
15743
15744    pub fn go_to_type_definition_split(
15745        &mut self,
15746        _: &GoToTypeDefinitionSplit,
15747        window: &mut Window,
15748        cx: &mut Context<Self>,
15749    ) -> Task<Result<Navigated>> {
15750        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15751    }
15752
15753    fn go_to_definition_of_kind(
15754        &mut self,
15755        kind: GotoDefinitionKind,
15756        split: bool,
15757        window: &mut Window,
15758        cx: &mut Context<Self>,
15759    ) -> Task<Result<Navigated>> {
15760        let Some(provider) = self.semantics_provider.clone() else {
15761            return Task::ready(Ok(Navigated::No));
15762        };
15763        let head = self.selections.newest::<usize>(cx).head();
15764        let buffer = self.buffer.read(cx);
15765        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15766            return Task::ready(Ok(Navigated::No));
15767        };
15768        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15769            return Task::ready(Ok(Navigated::No));
15770        };
15771
15772        cx.spawn_in(window, async move |editor, cx| {
15773            let definitions = definitions.await?;
15774            let navigated = editor
15775                .update_in(cx, |editor, window, cx| {
15776                    editor.navigate_to_hover_links(
15777                        Some(kind),
15778                        definitions
15779                            .into_iter()
15780                            .filter(|location| {
15781                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15782                            })
15783                            .map(HoverLink::Text)
15784                            .collect::<Vec<_>>(),
15785                        split,
15786                        window,
15787                        cx,
15788                    )
15789                })?
15790                .await?;
15791            anyhow::Ok(navigated)
15792        })
15793    }
15794
15795    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15796        let selection = self.selections.newest_anchor();
15797        let head = selection.head();
15798        let tail = selection.tail();
15799
15800        let Some((buffer, start_position)) =
15801            self.buffer.read(cx).text_anchor_for_position(head, cx)
15802        else {
15803            return;
15804        };
15805
15806        let end_position = if head != tail {
15807            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15808                return;
15809            };
15810            Some(pos)
15811        } else {
15812            None
15813        };
15814
15815        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15816            let url = if let Some(end_pos) = end_position {
15817                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15818            } else {
15819                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15820            };
15821
15822            if let Some(url) = url {
15823                editor.update(cx, |_, cx| {
15824                    cx.open_url(&url);
15825                })
15826            } else {
15827                Ok(())
15828            }
15829        });
15830
15831        url_finder.detach();
15832    }
15833
15834    pub fn open_selected_filename(
15835        &mut self,
15836        _: &OpenSelectedFilename,
15837        window: &mut Window,
15838        cx: &mut Context<Self>,
15839    ) {
15840        let Some(workspace) = self.workspace() else {
15841            return;
15842        };
15843
15844        let position = self.selections.newest_anchor().head();
15845
15846        let Some((buffer, buffer_position)) =
15847            self.buffer.read(cx).text_anchor_for_position(position, cx)
15848        else {
15849            return;
15850        };
15851
15852        let project = self.project.clone();
15853
15854        cx.spawn_in(window, async move |_, cx| {
15855            let result = find_file(&buffer, project, buffer_position, cx).await;
15856
15857            if let Some((_, path)) = result {
15858                workspace
15859                    .update_in(cx, |workspace, window, cx| {
15860                        workspace.open_resolved_path(path, window, cx)
15861                    })?
15862                    .await?;
15863            }
15864            anyhow::Ok(())
15865        })
15866        .detach();
15867    }
15868
15869    pub(crate) fn navigate_to_hover_links(
15870        &mut self,
15871        kind: Option<GotoDefinitionKind>,
15872        definitions: Vec<HoverLink>,
15873        split: bool,
15874        window: &mut Window,
15875        cx: &mut Context<Editor>,
15876    ) -> Task<Result<Navigated>> {
15877        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15878        let mut first_url_or_file = None;
15879        let definitions: Vec<_> = definitions
15880            .into_iter()
15881            .filter_map(|def| match def {
15882                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15883                HoverLink::InlayHint(lsp_location, server_id) => {
15884                    let computation =
15885                        self.compute_target_location(lsp_location, server_id, window, cx);
15886                    Some(cx.background_spawn(computation))
15887                }
15888                HoverLink::Url(url) => {
15889                    first_url_or_file = Some(Either::Left(url));
15890                    None
15891                }
15892                HoverLink::File(path) => {
15893                    first_url_or_file = Some(Either::Right(path));
15894                    None
15895                }
15896            })
15897            .collect();
15898
15899        let workspace = self.workspace();
15900
15901        cx.spawn_in(window, async move |editor, acx| {
15902            let mut locations: Vec<Location> = future::join_all(definitions)
15903                .await
15904                .into_iter()
15905                .filter_map(|location| location.transpose())
15906                .collect::<Result<_>>()
15907                .context("location tasks")?;
15908
15909            if locations.len() > 1 {
15910                let Some(workspace) = workspace else {
15911                    return Ok(Navigated::No);
15912                };
15913
15914                let tab_kind = match kind {
15915                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15916                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15917                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15918                    Some(GotoDefinitionKind::Type) => "Types",
15919                };
15920                let title = editor
15921                    .update_in(acx, |_, _, cx| {
15922                        let target = locations
15923                            .iter()
15924                            .map(|location| {
15925                                location
15926                                    .buffer
15927                                    .read(cx)
15928                                    .text_for_range(location.range.clone())
15929                                    .collect::<String>()
15930                            })
15931                            .filter(|text| !text.contains('\n'))
15932                            .unique()
15933                            .take(3)
15934                            .join(", ");
15935                        if target.is_empty() {
15936                            tab_kind.to_owned()
15937                        } else {
15938                            format!("{tab_kind} for {target}")
15939                        }
15940                    })
15941                    .context("buffer title")?;
15942
15943                let opened = workspace
15944                    .update_in(acx, |workspace, window, cx| {
15945                        Self::open_locations_in_multibuffer(
15946                            workspace,
15947                            locations,
15948                            title,
15949                            split,
15950                            MultibufferSelectionMode::First,
15951                            window,
15952                            cx,
15953                        )
15954                    })
15955                    .is_ok();
15956
15957                anyhow::Ok(Navigated::from_bool(opened))
15958            } else if locations.is_empty() {
15959                // If there is one definition, just open it directly
15960                match first_url_or_file {
15961                    Some(Either::Left(url)) => {
15962                        acx.update(|_, cx| cx.open_url(&url))?;
15963                        Ok(Navigated::Yes)
15964                    }
15965                    Some(Either::Right(path)) => {
15966                        let Some(workspace) = workspace else {
15967                            return Ok(Navigated::No);
15968                        };
15969
15970                        workspace
15971                            .update_in(acx, |workspace, window, cx| {
15972                                workspace.open_resolved_path(path, window, cx)
15973                            })?
15974                            .await?;
15975                        Ok(Navigated::Yes)
15976                    }
15977                    None => Ok(Navigated::No),
15978                }
15979            } else {
15980                let Some(workspace) = workspace else {
15981                    return Ok(Navigated::No);
15982                };
15983
15984                let target = locations.pop().unwrap();
15985                editor.update_in(acx, |editor, window, cx| {
15986                    let pane = workspace.read(cx).active_pane().clone();
15987
15988                    let range = target.range.to_point(target.buffer.read(cx));
15989                    let range = editor.range_for_match(&range);
15990                    let range = collapse_multiline_range(range);
15991
15992                    if !split
15993                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15994                    {
15995                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15996                    } else {
15997                        window.defer(cx, move |window, cx| {
15998                            let target_editor: Entity<Self> =
15999                                workspace.update(cx, |workspace, cx| {
16000                                    let pane = if split {
16001                                        workspace.adjacent_pane(window, cx)
16002                                    } else {
16003                                        workspace.active_pane().clone()
16004                                    };
16005
16006                                    workspace.open_project_item(
16007                                        pane,
16008                                        target.buffer.clone(),
16009                                        true,
16010                                        true,
16011                                        window,
16012                                        cx,
16013                                    )
16014                                });
16015                            target_editor.update(cx, |target_editor, cx| {
16016                                // When selecting a definition in a different buffer, disable the nav history
16017                                // to avoid creating a history entry at the previous cursor location.
16018                                pane.update(cx, |pane, _| pane.disable_history());
16019                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16020                                pane.update(cx, |pane, _| pane.enable_history());
16021                            });
16022                        });
16023                    }
16024                    Navigated::Yes
16025                })
16026            }
16027        })
16028    }
16029
16030    fn compute_target_location(
16031        &self,
16032        lsp_location: lsp::Location,
16033        server_id: LanguageServerId,
16034        window: &mut Window,
16035        cx: &mut Context<Self>,
16036    ) -> Task<anyhow::Result<Option<Location>>> {
16037        let Some(project) = self.project.clone() else {
16038            return Task::ready(Ok(None));
16039        };
16040
16041        cx.spawn_in(window, async move |editor, cx| {
16042            let location_task = editor.update(cx, |_, cx| {
16043                project.update(cx, |project, cx| {
16044                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16045                })
16046            })?;
16047            let location = Some({
16048                let target_buffer_handle = location_task.await.context("open local buffer")?;
16049                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16050                    let target_start = target_buffer
16051                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16052                    let target_end = target_buffer
16053                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16054                    target_buffer.anchor_after(target_start)
16055                        ..target_buffer.anchor_before(target_end)
16056                })?;
16057                Location {
16058                    buffer: target_buffer_handle,
16059                    range,
16060                }
16061            });
16062            Ok(location)
16063        })
16064    }
16065
16066    pub fn find_all_references(
16067        &mut self,
16068        _: &FindAllReferences,
16069        window: &mut Window,
16070        cx: &mut Context<Self>,
16071    ) -> Option<Task<Result<Navigated>>> {
16072        let selection = self.selections.newest::<usize>(cx);
16073        let multi_buffer = self.buffer.read(cx);
16074        let head = selection.head();
16075
16076        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16077        let head_anchor = multi_buffer_snapshot.anchor_at(
16078            head,
16079            if head < selection.tail() {
16080                Bias::Right
16081            } else {
16082                Bias::Left
16083            },
16084        );
16085
16086        match self
16087            .find_all_references_task_sources
16088            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16089        {
16090            Ok(_) => {
16091                log::info!(
16092                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16093                );
16094                return None;
16095            }
16096            Err(i) => {
16097                self.find_all_references_task_sources.insert(i, head_anchor);
16098            }
16099        }
16100
16101        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16102        let workspace = self.workspace()?;
16103        let project = workspace.read(cx).project().clone();
16104        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16105        Some(cx.spawn_in(window, async move |editor, cx| {
16106            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16107                if let Ok(i) = editor
16108                    .find_all_references_task_sources
16109                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16110                {
16111                    editor.find_all_references_task_sources.remove(i);
16112                }
16113            });
16114
16115            let locations = references.await?;
16116            if locations.is_empty() {
16117                return anyhow::Ok(Navigated::No);
16118            }
16119
16120            workspace.update_in(cx, |workspace, window, cx| {
16121                let target = locations
16122                    .iter()
16123                    .map(|location| {
16124                        location
16125                            .buffer
16126                            .read(cx)
16127                            .text_for_range(location.range.clone())
16128                            .collect::<String>()
16129                    })
16130                    .filter(|text| !text.contains('\n'))
16131                    .unique()
16132                    .take(3)
16133                    .join(", ");
16134                let title = if target.is_empty() {
16135                    "References".to_owned()
16136                } else {
16137                    format!("References to {target}")
16138                };
16139                Self::open_locations_in_multibuffer(
16140                    workspace,
16141                    locations,
16142                    title,
16143                    false,
16144                    MultibufferSelectionMode::First,
16145                    window,
16146                    cx,
16147                );
16148                Navigated::Yes
16149            })
16150        }))
16151    }
16152
16153    /// Opens a multibuffer with the given project locations in it
16154    pub fn open_locations_in_multibuffer(
16155        workspace: &mut Workspace,
16156        mut locations: Vec<Location>,
16157        title: String,
16158        split: bool,
16159        multibuffer_selection_mode: MultibufferSelectionMode,
16160        window: &mut Window,
16161        cx: &mut Context<Workspace>,
16162    ) {
16163        if locations.is_empty() {
16164            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16165            return;
16166        }
16167
16168        // If there are multiple definitions, open them in a multibuffer
16169        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16170        let mut locations = locations.into_iter().peekable();
16171        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16172        let capability = workspace.project().read(cx).capability();
16173
16174        let excerpt_buffer = cx.new(|cx| {
16175            let mut multibuffer = MultiBuffer::new(capability);
16176            while let Some(location) = locations.next() {
16177                let buffer = location.buffer.read(cx);
16178                let mut ranges_for_buffer = Vec::new();
16179                let range = location.range.to_point(buffer);
16180                ranges_for_buffer.push(range.clone());
16181
16182                while let Some(next_location) = locations.peek() {
16183                    if next_location.buffer == location.buffer {
16184                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16185                        locations.next();
16186                    } else {
16187                        break;
16188                    }
16189                }
16190
16191                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16192                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16193                    PathKey::for_buffer(&location.buffer, cx),
16194                    location.buffer.clone(),
16195                    ranges_for_buffer,
16196                    DEFAULT_MULTIBUFFER_CONTEXT,
16197                    cx,
16198                );
16199                ranges.extend(new_ranges)
16200            }
16201
16202            multibuffer.with_title(title)
16203        });
16204
16205        let editor = cx.new(|cx| {
16206            Editor::for_multibuffer(
16207                excerpt_buffer,
16208                Some(workspace.project().clone()),
16209                window,
16210                cx,
16211            )
16212        });
16213        editor.update(cx, |editor, cx| {
16214            match multibuffer_selection_mode {
16215                MultibufferSelectionMode::First => {
16216                    if let Some(first_range) = ranges.first() {
16217                        editor.change_selections(
16218                            SelectionEffects::no_scroll(),
16219                            window,
16220                            cx,
16221                            |selections| {
16222                                selections.clear_disjoint();
16223                                selections
16224                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16225                            },
16226                        );
16227                    }
16228                    editor.highlight_background::<Self>(
16229                        &ranges,
16230                        |theme| theme.colors().editor_highlighted_line_background,
16231                        cx,
16232                    );
16233                }
16234                MultibufferSelectionMode::All => {
16235                    editor.change_selections(
16236                        SelectionEffects::no_scroll(),
16237                        window,
16238                        cx,
16239                        |selections| {
16240                            selections.clear_disjoint();
16241                            selections.select_anchor_ranges(ranges);
16242                        },
16243                    );
16244                }
16245            }
16246            editor.register_buffers_with_language_servers(cx);
16247        });
16248
16249        let item = Box::new(editor);
16250        let item_id = item.item_id();
16251
16252        if split {
16253            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16254        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16255            let (preview_item_id, preview_item_idx) =
16256                workspace.active_pane().read_with(cx, |pane, _| {
16257                    (pane.preview_item_id(), pane.preview_item_idx())
16258                });
16259
16260            workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16261
16262            if let Some(preview_item_id) = preview_item_id {
16263                workspace.active_pane().update(cx, |pane, cx| {
16264                    pane.remove_item(preview_item_id, false, false, window, cx);
16265                });
16266            }
16267        } else {
16268            workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16269        }
16270        workspace.active_pane().update(cx, |pane, cx| {
16271            pane.set_preview_item_id(Some(item_id), cx);
16272        });
16273    }
16274
16275    pub fn rename(
16276        &mut self,
16277        _: &Rename,
16278        window: &mut Window,
16279        cx: &mut Context<Self>,
16280    ) -> Option<Task<Result<()>>> {
16281        use language::ToOffset as _;
16282
16283        let provider = self.semantics_provider.clone()?;
16284        let selection = self.selections.newest_anchor().clone();
16285        let (cursor_buffer, cursor_buffer_position) = self
16286            .buffer
16287            .read(cx)
16288            .text_anchor_for_position(selection.head(), cx)?;
16289        let (tail_buffer, cursor_buffer_position_end) = self
16290            .buffer
16291            .read(cx)
16292            .text_anchor_for_position(selection.tail(), cx)?;
16293        if tail_buffer != cursor_buffer {
16294            return None;
16295        }
16296
16297        let snapshot = cursor_buffer.read(cx).snapshot();
16298        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16299        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16300        let prepare_rename = provider
16301            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16302            .unwrap_or_else(|| Task::ready(Ok(None)));
16303        drop(snapshot);
16304
16305        Some(cx.spawn_in(window, async move |this, cx| {
16306            let rename_range = if let Some(range) = prepare_rename.await? {
16307                Some(range)
16308            } else {
16309                this.update(cx, |this, cx| {
16310                    let buffer = this.buffer.read(cx).snapshot(cx);
16311                    let mut buffer_highlights = this
16312                        .document_highlights_for_position(selection.head(), &buffer)
16313                        .filter(|highlight| {
16314                            highlight.start.excerpt_id == selection.head().excerpt_id
16315                                && highlight.end.excerpt_id == selection.head().excerpt_id
16316                        });
16317                    buffer_highlights
16318                        .next()
16319                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16320                })?
16321            };
16322            if let Some(rename_range) = rename_range {
16323                this.update_in(cx, |this, window, cx| {
16324                    let snapshot = cursor_buffer.read(cx).snapshot();
16325                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16326                    let cursor_offset_in_rename_range =
16327                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16328                    let cursor_offset_in_rename_range_end =
16329                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16330
16331                    this.take_rename(false, window, cx);
16332                    let buffer = this.buffer.read(cx).read(cx);
16333                    let cursor_offset = selection.head().to_offset(&buffer);
16334                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16335                    let rename_end = rename_start + rename_buffer_range.len();
16336                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16337                    let mut old_highlight_id = None;
16338                    let old_name: Arc<str> = buffer
16339                        .chunks(rename_start..rename_end, true)
16340                        .map(|chunk| {
16341                            if old_highlight_id.is_none() {
16342                                old_highlight_id = chunk.syntax_highlight_id;
16343                            }
16344                            chunk.text
16345                        })
16346                        .collect::<String>()
16347                        .into();
16348
16349                    drop(buffer);
16350
16351                    // Position the selection in the rename editor so that it matches the current selection.
16352                    this.show_local_selections = false;
16353                    let rename_editor = cx.new(|cx| {
16354                        let mut editor = Editor::single_line(window, cx);
16355                        editor.buffer.update(cx, |buffer, cx| {
16356                            buffer.edit([(0..0, old_name.clone())], None, cx)
16357                        });
16358                        let rename_selection_range = match cursor_offset_in_rename_range
16359                            .cmp(&cursor_offset_in_rename_range_end)
16360                        {
16361                            Ordering::Equal => {
16362                                editor.select_all(&SelectAll, window, cx);
16363                                return editor;
16364                            }
16365                            Ordering::Less => {
16366                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16367                            }
16368                            Ordering::Greater => {
16369                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16370                            }
16371                        };
16372                        if rename_selection_range.end > old_name.len() {
16373                            editor.select_all(&SelectAll, window, cx);
16374                        } else {
16375                            editor.change_selections(Default::default(), window, cx, |s| {
16376                                s.select_ranges([rename_selection_range]);
16377                            });
16378                        }
16379                        editor
16380                    });
16381                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16382                        if e == &EditorEvent::Focused {
16383                            cx.emit(EditorEvent::FocusedIn)
16384                        }
16385                    })
16386                    .detach();
16387
16388                    let write_highlights =
16389                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16390                    let read_highlights =
16391                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16392                    let ranges = write_highlights
16393                        .iter()
16394                        .flat_map(|(_, ranges)| ranges.iter())
16395                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16396                        .cloned()
16397                        .collect();
16398
16399                    this.highlight_text::<Rename>(
16400                        ranges,
16401                        HighlightStyle {
16402                            fade_out: Some(0.6),
16403                            ..Default::default()
16404                        },
16405                        cx,
16406                    );
16407                    let rename_focus_handle = rename_editor.focus_handle(cx);
16408                    window.focus(&rename_focus_handle);
16409                    let block_id = this.insert_blocks(
16410                        [BlockProperties {
16411                            style: BlockStyle::Flex,
16412                            placement: BlockPlacement::Below(range.start),
16413                            height: Some(1),
16414                            render: Arc::new({
16415                                let rename_editor = rename_editor.clone();
16416                                move |cx: &mut BlockContext| {
16417                                    let mut text_style = cx.editor_style.text.clone();
16418                                    if let Some(highlight_style) = old_highlight_id
16419                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16420                                    {
16421                                        text_style = text_style.highlight(highlight_style);
16422                                    }
16423                                    div()
16424                                        .block_mouse_except_scroll()
16425                                        .pl(cx.anchor_x)
16426                                        .child(EditorElement::new(
16427                                            &rename_editor,
16428                                            EditorStyle {
16429                                                background: cx.theme().system().transparent,
16430                                                local_player: cx.editor_style.local_player,
16431                                                text: text_style,
16432                                                scrollbar_width: cx.editor_style.scrollbar_width,
16433                                                syntax: cx.editor_style.syntax.clone(),
16434                                                status: cx.editor_style.status.clone(),
16435                                                inlay_hints_style: HighlightStyle {
16436                                                    font_weight: Some(FontWeight::BOLD),
16437                                                    ..make_inlay_hints_style(cx.app)
16438                                                },
16439                                                edit_prediction_styles: make_suggestion_styles(
16440                                                    cx.app,
16441                                                ),
16442                                                ..EditorStyle::default()
16443                                            },
16444                                        ))
16445                                        .into_any_element()
16446                                }
16447                            }),
16448                            priority: 0,
16449                        }],
16450                        Some(Autoscroll::fit()),
16451                        cx,
16452                    )[0];
16453                    this.pending_rename = Some(RenameState {
16454                        range,
16455                        old_name,
16456                        editor: rename_editor,
16457                        block_id,
16458                    });
16459                })?;
16460            }
16461
16462            Ok(())
16463        }))
16464    }
16465
16466    pub fn confirm_rename(
16467        &mut self,
16468        _: &ConfirmRename,
16469        window: &mut Window,
16470        cx: &mut Context<Self>,
16471    ) -> Option<Task<Result<()>>> {
16472        let rename = self.take_rename(false, window, cx)?;
16473        let workspace = self.workspace()?.downgrade();
16474        let (buffer, start) = self
16475            .buffer
16476            .read(cx)
16477            .text_anchor_for_position(rename.range.start, cx)?;
16478        let (end_buffer, _) = self
16479            .buffer
16480            .read(cx)
16481            .text_anchor_for_position(rename.range.end, cx)?;
16482        if buffer != end_buffer {
16483            return None;
16484        }
16485
16486        let old_name = rename.old_name;
16487        let new_name = rename.editor.read(cx).text(cx);
16488
16489        let rename = self.semantics_provider.as_ref()?.perform_rename(
16490            &buffer,
16491            start,
16492            new_name.clone(),
16493            cx,
16494        )?;
16495
16496        Some(cx.spawn_in(window, async move |editor, cx| {
16497            let project_transaction = rename.await?;
16498            Self::open_project_transaction(
16499                &editor,
16500                workspace,
16501                project_transaction,
16502                format!("Rename: {}{}", old_name, new_name),
16503                cx,
16504            )
16505            .await?;
16506
16507            editor.update(cx, |editor, cx| {
16508                editor.refresh_document_highlights(cx);
16509            })?;
16510            Ok(())
16511        }))
16512    }
16513
16514    fn take_rename(
16515        &mut self,
16516        moving_cursor: bool,
16517        window: &mut Window,
16518        cx: &mut Context<Self>,
16519    ) -> Option<RenameState> {
16520        let rename = self.pending_rename.take()?;
16521        if rename.editor.focus_handle(cx).is_focused(window) {
16522            window.focus(&self.focus_handle);
16523        }
16524
16525        self.remove_blocks(
16526            [rename.block_id].into_iter().collect(),
16527            Some(Autoscroll::fit()),
16528            cx,
16529        );
16530        self.clear_highlights::<Rename>(cx);
16531        self.show_local_selections = true;
16532
16533        if moving_cursor {
16534            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16535                editor.selections.newest::<usize>(cx).head()
16536            });
16537
16538            // Update the selection to match the position of the selection inside
16539            // the rename editor.
16540            let snapshot = self.buffer.read(cx).read(cx);
16541            let rename_range = rename.range.to_offset(&snapshot);
16542            let cursor_in_editor = snapshot
16543                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16544                .min(rename_range.end);
16545            drop(snapshot);
16546
16547            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16548                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16549            });
16550        } else {
16551            self.refresh_document_highlights(cx);
16552        }
16553
16554        Some(rename)
16555    }
16556
16557    pub fn pending_rename(&self) -> Option<&RenameState> {
16558        self.pending_rename.as_ref()
16559    }
16560
16561    fn format(
16562        &mut self,
16563        _: &Format,
16564        window: &mut Window,
16565        cx: &mut Context<Self>,
16566    ) -> Option<Task<Result<()>>> {
16567        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16568
16569        let project = match &self.project {
16570            Some(project) => project.clone(),
16571            None => return None,
16572        };
16573
16574        Some(self.perform_format(
16575            project,
16576            FormatTrigger::Manual,
16577            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16578            window,
16579            cx,
16580        ))
16581    }
16582
16583    fn format_selections(
16584        &mut self,
16585        _: &FormatSelections,
16586        window: &mut Window,
16587        cx: &mut Context<Self>,
16588    ) -> Option<Task<Result<()>>> {
16589        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16590
16591        let project = match &self.project {
16592            Some(project) => project.clone(),
16593            None => return None,
16594        };
16595
16596        let ranges = self
16597            .selections
16598            .all_adjusted(cx)
16599            .into_iter()
16600            .map(|selection| selection.range())
16601            .collect_vec();
16602
16603        Some(self.perform_format(
16604            project,
16605            FormatTrigger::Manual,
16606            FormatTarget::Ranges(ranges),
16607            window,
16608            cx,
16609        ))
16610    }
16611
16612    fn perform_format(
16613        &mut self,
16614        project: Entity<Project>,
16615        trigger: FormatTrigger,
16616        target: FormatTarget,
16617        window: &mut Window,
16618        cx: &mut Context<Self>,
16619    ) -> Task<Result<()>> {
16620        let buffer = self.buffer.clone();
16621        let (buffers, target) = match target {
16622            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16623            FormatTarget::Ranges(selection_ranges) => {
16624                let multi_buffer = buffer.read(cx);
16625                let snapshot = multi_buffer.read(cx);
16626                let mut buffers = HashSet::default();
16627                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16628                    BTreeMap::new();
16629                for selection_range in selection_ranges {
16630                    for (buffer, buffer_range, _) in
16631                        snapshot.range_to_buffer_ranges(selection_range)
16632                    {
16633                        let buffer_id = buffer.remote_id();
16634                        let start = buffer.anchor_before(buffer_range.start);
16635                        let end = buffer.anchor_after(buffer_range.end);
16636                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16637                        buffer_id_to_ranges
16638                            .entry(buffer_id)
16639                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16640                            .or_insert_with(|| vec![start..end]);
16641                    }
16642                }
16643                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16644            }
16645        };
16646
16647        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16648        let selections_prev = transaction_id_prev
16649            .and_then(|transaction_id_prev| {
16650                // default to selections as they were after the last edit, if we have them,
16651                // instead of how they are now.
16652                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16653                // will take you back to where you made the last edit, instead of staying where you scrolled
16654                self.selection_history
16655                    .transaction(transaction_id_prev)
16656                    .map(|t| t.0.clone())
16657            })
16658            .unwrap_or_else(|| {
16659                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16660                self.selections.disjoint_anchors()
16661            });
16662
16663        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16664        let format = project.update(cx, |project, cx| {
16665            project.format(buffers, target, true, trigger, cx)
16666        });
16667
16668        cx.spawn_in(window, async move |editor, cx| {
16669            let transaction = futures::select_biased! {
16670                transaction = format.log_err().fuse() => transaction,
16671                () = timeout => {
16672                    log::warn!("timed out waiting for formatting");
16673                    None
16674                }
16675            };
16676
16677            buffer
16678                .update(cx, |buffer, cx| {
16679                    if let Some(transaction) = transaction
16680                        && !buffer.is_singleton()
16681                    {
16682                        buffer.push_transaction(&transaction.0, cx);
16683                    }
16684                    cx.notify();
16685                })
16686                .ok();
16687
16688            if let Some(transaction_id_now) =
16689                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16690            {
16691                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16692                if has_new_transaction {
16693                    _ = editor.update(cx, |editor, _| {
16694                        editor
16695                            .selection_history
16696                            .insert_transaction(transaction_id_now, selections_prev);
16697                    });
16698                }
16699            }
16700
16701            Ok(())
16702        })
16703    }
16704
16705    fn organize_imports(
16706        &mut self,
16707        _: &OrganizeImports,
16708        window: &mut Window,
16709        cx: &mut Context<Self>,
16710    ) -> Option<Task<Result<()>>> {
16711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16712        let project = match &self.project {
16713            Some(project) => project.clone(),
16714            None => return None,
16715        };
16716        Some(self.perform_code_action_kind(
16717            project,
16718            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16719            window,
16720            cx,
16721        ))
16722    }
16723
16724    fn perform_code_action_kind(
16725        &mut self,
16726        project: Entity<Project>,
16727        kind: CodeActionKind,
16728        window: &mut Window,
16729        cx: &mut Context<Self>,
16730    ) -> Task<Result<()>> {
16731        let buffer = self.buffer.clone();
16732        let buffers = buffer.read(cx).all_buffers();
16733        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16734        let apply_action = project.update(cx, |project, cx| {
16735            project.apply_code_action_kind(buffers, kind, true, cx)
16736        });
16737        cx.spawn_in(window, async move |_, cx| {
16738            let transaction = futures::select_biased! {
16739                () = timeout => {
16740                    log::warn!("timed out waiting for executing code action");
16741                    None
16742                }
16743                transaction = apply_action.log_err().fuse() => transaction,
16744            };
16745            buffer
16746                .update(cx, |buffer, cx| {
16747                    // check if we need this
16748                    if let Some(transaction) = transaction
16749                        && !buffer.is_singleton()
16750                    {
16751                        buffer.push_transaction(&transaction.0, cx);
16752                    }
16753                    cx.notify();
16754                })
16755                .ok();
16756            Ok(())
16757        })
16758    }
16759
16760    pub fn restart_language_server(
16761        &mut self,
16762        _: &RestartLanguageServer,
16763        _: &mut Window,
16764        cx: &mut Context<Self>,
16765    ) {
16766        if let Some(project) = self.project.clone() {
16767            self.buffer.update(cx, |multi_buffer, cx| {
16768                project.update(cx, |project, cx| {
16769                    project.restart_language_servers_for_buffers(
16770                        multi_buffer.all_buffers().into_iter().collect(),
16771                        HashSet::default(),
16772                        cx,
16773                    );
16774                });
16775            })
16776        }
16777    }
16778
16779    pub fn stop_language_server(
16780        &mut self,
16781        _: &StopLanguageServer,
16782        _: &mut Window,
16783        cx: &mut Context<Self>,
16784    ) {
16785        if let Some(project) = self.project.clone() {
16786            self.buffer.update(cx, |multi_buffer, cx| {
16787                project.update(cx, |project, cx| {
16788                    project.stop_language_servers_for_buffers(
16789                        multi_buffer.all_buffers().into_iter().collect(),
16790                        HashSet::default(),
16791                        cx,
16792                    );
16793                    cx.emit(project::Event::RefreshInlayHints);
16794                });
16795            });
16796        }
16797    }
16798
16799    fn cancel_language_server_work(
16800        workspace: &mut Workspace,
16801        _: &actions::CancelLanguageServerWork,
16802        _: &mut Window,
16803        cx: &mut Context<Workspace>,
16804    ) {
16805        let project = workspace.project();
16806        let buffers = workspace
16807            .active_item(cx)
16808            .and_then(|item| item.act_as::<Editor>(cx))
16809            .map_or(HashSet::default(), |editor| {
16810                editor.read(cx).buffer.read(cx).all_buffers()
16811            });
16812        project.update(cx, |project, cx| {
16813            project.cancel_language_server_work_for_buffers(buffers, cx);
16814        });
16815    }
16816
16817    fn show_character_palette(
16818        &mut self,
16819        _: &ShowCharacterPalette,
16820        window: &mut Window,
16821        _: &mut Context<Self>,
16822    ) {
16823        window.show_character_palette();
16824    }
16825
16826    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16827        if !self.diagnostics_enabled() {
16828            return;
16829        }
16830
16831        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16832            let buffer = self.buffer.read(cx).snapshot(cx);
16833            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16834            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16835            let is_valid = buffer
16836                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16837                .any(|entry| {
16838                    entry.diagnostic.is_primary
16839                        && !entry.range.is_empty()
16840                        && entry.range.start == primary_range_start
16841                        && entry.diagnostic.message == active_diagnostics.active_message
16842                });
16843
16844            if !is_valid {
16845                self.dismiss_diagnostics(cx);
16846            }
16847        }
16848    }
16849
16850    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16851        match &self.active_diagnostics {
16852            ActiveDiagnostic::Group(group) => Some(group),
16853            _ => None,
16854        }
16855    }
16856
16857    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16858        if !self.diagnostics_enabled() {
16859            return;
16860        }
16861        self.dismiss_diagnostics(cx);
16862        self.active_diagnostics = ActiveDiagnostic::All;
16863    }
16864
16865    fn activate_diagnostics(
16866        &mut self,
16867        buffer_id: BufferId,
16868        diagnostic: DiagnosticEntry<usize>,
16869        window: &mut Window,
16870        cx: &mut Context<Self>,
16871    ) {
16872        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16873            return;
16874        }
16875        self.dismiss_diagnostics(cx);
16876        let snapshot = self.snapshot(window, cx);
16877        let buffer = self.buffer.read(cx).snapshot(cx);
16878        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16879            return;
16880        };
16881
16882        let diagnostic_group = buffer
16883            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16884            .collect::<Vec<_>>();
16885
16886        let blocks =
16887            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16888
16889        let blocks = self.display_map.update(cx, |display_map, cx| {
16890            display_map.insert_blocks(blocks, cx).into_iter().collect()
16891        });
16892        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16893            active_range: buffer.anchor_before(diagnostic.range.start)
16894                ..buffer.anchor_after(diagnostic.range.end),
16895            active_message: diagnostic.diagnostic.message.clone(),
16896            group_id: diagnostic.diagnostic.group_id,
16897            blocks,
16898        });
16899        cx.notify();
16900    }
16901
16902    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16903        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16904            return;
16905        };
16906
16907        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16908        if let ActiveDiagnostic::Group(group) = prev {
16909            self.display_map.update(cx, |display_map, cx| {
16910                display_map.remove_blocks(group.blocks, cx);
16911            });
16912            cx.notify();
16913        }
16914    }
16915
16916    /// Disable inline diagnostics rendering for this editor.
16917    pub fn disable_inline_diagnostics(&mut self) {
16918        self.inline_diagnostics_enabled = false;
16919        self.inline_diagnostics_update = Task::ready(());
16920        self.inline_diagnostics.clear();
16921    }
16922
16923    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16924        self.diagnostics_enabled = false;
16925        self.dismiss_diagnostics(cx);
16926        self.inline_diagnostics_update = Task::ready(());
16927        self.inline_diagnostics.clear();
16928    }
16929
16930    pub fn diagnostics_enabled(&self) -> bool {
16931        self.diagnostics_enabled && self.mode.is_full()
16932    }
16933
16934    pub fn inline_diagnostics_enabled(&self) -> bool {
16935        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16936    }
16937
16938    pub fn show_inline_diagnostics(&self) -> bool {
16939        self.show_inline_diagnostics
16940    }
16941
16942    pub fn toggle_inline_diagnostics(
16943        &mut self,
16944        _: &ToggleInlineDiagnostics,
16945        window: &mut Window,
16946        cx: &mut Context<Editor>,
16947    ) {
16948        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16949        self.refresh_inline_diagnostics(false, window, cx);
16950    }
16951
16952    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16953        self.diagnostics_max_severity = severity;
16954        self.display_map.update(cx, |display_map, _| {
16955            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16956        });
16957    }
16958
16959    pub fn toggle_diagnostics(
16960        &mut self,
16961        _: &ToggleDiagnostics,
16962        window: &mut Window,
16963        cx: &mut Context<Editor>,
16964    ) {
16965        if !self.diagnostics_enabled() {
16966            return;
16967        }
16968
16969        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16970            EditorSettings::get_global(cx)
16971                .diagnostics_max_severity
16972                .filter(|severity| severity != &DiagnosticSeverity::Off)
16973                .unwrap_or(DiagnosticSeverity::Hint)
16974        } else {
16975            DiagnosticSeverity::Off
16976        };
16977        self.set_max_diagnostics_severity(new_severity, cx);
16978        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16979            self.active_diagnostics = ActiveDiagnostic::None;
16980            self.inline_diagnostics_update = Task::ready(());
16981            self.inline_diagnostics.clear();
16982        } else {
16983            self.refresh_inline_diagnostics(false, window, cx);
16984        }
16985
16986        cx.notify();
16987    }
16988
16989    pub fn toggle_minimap(
16990        &mut self,
16991        _: &ToggleMinimap,
16992        window: &mut Window,
16993        cx: &mut Context<Editor>,
16994    ) {
16995        if self.supports_minimap(cx) {
16996            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16997        }
16998    }
16999
17000    fn refresh_inline_diagnostics(
17001        &mut self,
17002        debounce: bool,
17003        window: &mut Window,
17004        cx: &mut Context<Self>,
17005    ) {
17006        let max_severity = ProjectSettings::get_global(cx)
17007            .diagnostics
17008            .inline
17009            .max_severity
17010            .unwrap_or(self.diagnostics_max_severity);
17011
17012        if !self.inline_diagnostics_enabled()
17013            || !self.show_inline_diagnostics
17014            || max_severity == DiagnosticSeverity::Off
17015        {
17016            self.inline_diagnostics_update = Task::ready(());
17017            self.inline_diagnostics.clear();
17018            return;
17019        }
17020
17021        let debounce_ms = ProjectSettings::get_global(cx)
17022            .diagnostics
17023            .inline
17024            .update_debounce_ms;
17025        let debounce = if debounce && debounce_ms > 0 {
17026            Some(Duration::from_millis(debounce_ms))
17027        } else {
17028            None
17029        };
17030        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17031            if let Some(debounce) = debounce {
17032                cx.background_executor().timer(debounce).await;
17033            }
17034            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17035                editor
17036                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17037                    .ok()
17038            }) else {
17039                return;
17040            };
17041
17042            let new_inline_diagnostics = cx
17043                .background_spawn(async move {
17044                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17045                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17046                        let message = diagnostic_entry
17047                            .diagnostic
17048                            .message
17049                            .split_once('\n')
17050                            .map(|(line, _)| line)
17051                            .map(SharedString::new)
17052                            .unwrap_or_else(|| {
17053                                SharedString::from(diagnostic_entry.diagnostic.message)
17054                            });
17055                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17056                        let (Ok(i) | Err(i)) = inline_diagnostics
17057                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17058                        inline_diagnostics.insert(
17059                            i,
17060                            (
17061                                start_anchor,
17062                                InlineDiagnostic {
17063                                    message,
17064                                    group_id: diagnostic_entry.diagnostic.group_id,
17065                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17066                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17067                                    severity: diagnostic_entry.diagnostic.severity,
17068                                },
17069                            ),
17070                        );
17071                    }
17072                    inline_diagnostics
17073                })
17074                .await;
17075
17076            editor
17077                .update(cx, |editor, cx| {
17078                    editor.inline_diagnostics = new_inline_diagnostics;
17079                    cx.notify();
17080                })
17081                .ok();
17082        });
17083    }
17084
17085    fn pull_diagnostics(
17086        &mut self,
17087        buffer_id: Option<BufferId>,
17088        window: &Window,
17089        cx: &mut Context<Self>,
17090    ) -> Option<()> {
17091        if !self.mode().is_full() {
17092            return None;
17093        }
17094        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17095            .diagnostics
17096            .lsp_pull_diagnostics;
17097        if !pull_diagnostics_settings.enabled {
17098            return None;
17099        }
17100        let project = self.project()?.downgrade();
17101        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17102        let mut buffers = self.buffer.read(cx).all_buffers();
17103        if let Some(buffer_id) = buffer_id {
17104            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17105        }
17106
17107        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17108            cx.background_executor().timer(debounce).await;
17109
17110            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17111                buffers
17112                    .into_iter()
17113                    .filter_map(|buffer| {
17114                        project
17115                            .update(cx, |project, cx| {
17116                                project.lsp_store().update(cx, |lsp_store, cx| {
17117                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17118                                })
17119                            })
17120                            .ok()
17121                    })
17122                    .collect::<FuturesUnordered<_>>()
17123            }) else {
17124                return;
17125            };
17126
17127            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17128                match pull_task {
17129                    Ok(()) => {
17130                        if editor
17131                            .update_in(cx, |editor, window, cx| {
17132                                editor.update_diagnostics_state(window, cx);
17133                            })
17134                            .is_err()
17135                        {
17136                            return;
17137                        }
17138                    }
17139                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17140                }
17141            }
17142        });
17143
17144        Some(())
17145    }
17146
17147    pub fn set_selections_from_remote(
17148        &mut self,
17149        selections: Vec<Selection<Anchor>>,
17150        pending_selection: Option<Selection<Anchor>>,
17151        window: &mut Window,
17152        cx: &mut Context<Self>,
17153    ) {
17154        let old_cursor_position = self.selections.newest_anchor().head();
17155        self.selections.change_with(cx, |s| {
17156            s.select_anchors(selections);
17157            if let Some(pending_selection) = pending_selection {
17158                s.set_pending(pending_selection, SelectMode::Character);
17159            } else {
17160                s.clear_pending();
17161            }
17162        });
17163        self.selections_did_change(
17164            false,
17165            &old_cursor_position,
17166            SelectionEffects::default(),
17167            window,
17168            cx,
17169        );
17170    }
17171
17172    pub fn transact(
17173        &mut self,
17174        window: &mut Window,
17175        cx: &mut Context<Self>,
17176        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17177    ) -> Option<TransactionId> {
17178        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17179            this.start_transaction_at(Instant::now(), window, cx);
17180            update(this, window, cx);
17181            this.end_transaction_at(Instant::now(), cx)
17182        })
17183    }
17184
17185    pub fn start_transaction_at(
17186        &mut self,
17187        now: Instant,
17188        window: &mut Window,
17189        cx: &mut Context<Self>,
17190    ) -> Option<TransactionId> {
17191        self.end_selection(window, cx);
17192        if let Some(tx_id) = self
17193            .buffer
17194            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17195        {
17196            self.selection_history
17197                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17198            cx.emit(EditorEvent::TransactionBegun {
17199                transaction_id: tx_id,
17200            });
17201            Some(tx_id)
17202        } else {
17203            None
17204        }
17205    }
17206
17207    pub fn end_transaction_at(
17208        &mut self,
17209        now: Instant,
17210        cx: &mut Context<Self>,
17211    ) -> Option<TransactionId> {
17212        if let Some(transaction_id) = self
17213            .buffer
17214            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17215        {
17216            if let Some((_, end_selections)) =
17217                self.selection_history.transaction_mut(transaction_id)
17218            {
17219                *end_selections = Some(self.selections.disjoint_anchors());
17220            } else {
17221                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17222            }
17223
17224            cx.emit(EditorEvent::Edited { transaction_id });
17225            Some(transaction_id)
17226        } else {
17227            None
17228        }
17229    }
17230
17231    pub fn modify_transaction_selection_history(
17232        &mut self,
17233        transaction_id: TransactionId,
17234        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17235    ) -> bool {
17236        self.selection_history
17237            .transaction_mut(transaction_id)
17238            .map(modify)
17239            .is_some()
17240    }
17241
17242    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17243        if self.selection_mark_mode {
17244            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17245                s.move_with(|_, sel| {
17246                    sel.collapse_to(sel.head(), SelectionGoal::None);
17247                });
17248            })
17249        }
17250        self.selection_mark_mode = true;
17251        cx.notify();
17252    }
17253
17254    pub fn swap_selection_ends(
17255        &mut self,
17256        _: &actions::SwapSelectionEnds,
17257        window: &mut Window,
17258        cx: &mut Context<Self>,
17259    ) {
17260        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17261            s.move_with(|_, sel| {
17262                if sel.start != sel.end {
17263                    sel.reversed = !sel.reversed
17264                }
17265            });
17266        });
17267        self.request_autoscroll(Autoscroll::newest(), cx);
17268        cx.notify();
17269    }
17270
17271    pub fn toggle_focus(
17272        workspace: &mut Workspace,
17273        _: &actions::ToggleFocus,
17274        window: &mut Window,
17275        cx: &mut Context<Workspace>,
17276    ) {
17277        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17278            return;
17279        };
17280        workspace.activate_item(&item, true, true, window, cx);
17281    }
17282
17283    pub fn toggle_fold(
17284        &mut self,
17285        _: &actions::ToggleFold,
17286        window: &mut Window,
17287        cx: &mut Context<Self>,
17288    ) {
17289        if self.is_singleton(cx) {
17290            let selection = self.selections.newest::<Point>(cx);
17291
17292            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17293            let range = if selection.is_empty() {
17294                let point = selection.head().to_display_point(&display_map);
17295                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17296                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17297                    .to_point(&display_map);
17298                start..end
17299            } else {
17300                selection.range()
17301            };
17302            if display_map.folds_in_range(range).next().is_some() {
17303                self.unfold_lines(&Default::default(), window, cx)
17304            } else {
17305                self.fold(&Default::default(), window, cx)
17306            }
17307        } else {
17308            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17309            let buffer_ids: HashSet<_> = self
17310                .selections
17311                .disjoint_anchor_ranges()
17312                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17313                .collect();
17314
17315            let should_unfold = buffer_ids
17316                .iter()
17317                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17318
17319            for buffer_id in buffer_ids {
17320                if should_unfold {
17321                    self.unfold_buffer(buffer_id, cx);
17322                } else {
17323                    self.fold_buffer(buffer_id, cx);
17324                }
17325            }
17326        }
17327    }
17328
17329    pub fn toggle_fold_recursive(
17330        &mut self,
17331        _: &actions::ToggleFoldRecursive,
17332        window: &mut Window,
17333        cx: &mut Context<Self>,
17334    ) {
17335        let selection = self.selections.newest::<Point>(cx);
17336
17337        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17338        let range = if selection.is_empty() {
17339            let point = selection.head().to_display_point(&display_map);
17340            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17341            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17342                .to_point(&display_map);
17343            start..end
17344        } else {
17345            selection.range()
17346        };
17347        if display_map.folds_in_range(range).next().is_some() {
17348            self.unfold_recursive(&Default::default(), window, cx)
17349        } else {
17350            self.fold_recursive(&Default::default(), window, cx)
17351        }
17352    }
17353
17354    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17355        if self.is_singleton(cx) {
17356            let mut to_fold = Vec::new();
17357            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17358            let selections = self.selections.all_adjusted(cx);
17359
17360            for selection in selections {
17361                let range = selection.range().sorted();
17362                let buffer_start_row = range.start.row;
17363
17364                if range.start.row != range.end.row {
17365                    let mut found = false;
17366                    let mut row = range.start.row;
17367                    while row <= range.end.row {
17368                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17369                        {
17370                            found = true;
17371                            row = crease.range().end.row + 1;
17372                            to_fold.push(crease);
17373                        } else {
17374                            row += 1
17375                        }
17376                    }
17377                    if found {
17378                        continue;
17379                    }
17380                }
17381
17382                for row in (0..=range.start.row).rev() {
17383                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17384                        && crease.range().end.row >= buffer_start_row
17385                    {
17386                        to_fold.push(crease);
17387                        if row <= range.start.row {
17388                            break;
17389                        }
17390                    }
17391                }
17392            }
17393
17394            self.fold_creases(to_fold, true, window, cx);
17395        } else {
17396            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17397            let buffer_ids = self
17398                .selections
17399                .disjoint_anchor_ranges()
17400                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17401                .collect::<HashSet<_>>();
17402            for buffer_id in buffer_ids {
17403                self.fold_buffer(buffer_id, cx);
17404            }
17405        }
17406    }
17407
17408    pub fn toggle_fold_all(
17409        &mut self,
17410        _: &actions::ToggleFoldAll,
17411        window: &mut Window,
17412        cx: &mut Context<Self>,
17413    ) {
17414        if self.buffer.read(cx).is_singleton() {
17415            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17416            let has_folds = display_map
17417                .folds_in_range(0..display_map.buffer_snapshot.len())
17418                .next()
17419                .is_some();
17420
17421            if has_folds {
17422                self.unfold_all(&actions::UnfoldAll, window, cx);
17423            } else {
17424                self.fold_all(&actions::FoldAll, window, cx);
17425            }
17426        } else {
17427            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17428            let should_unfold = buffer_ids
17429                .iter()
17430                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17431
17432            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17433                editor
17434                    .update_in(cx, |editor, _, cx| {
17435                        for buffer_id in buffer_ids {
17436                            if should_unfold {
17437                                editor.unfold_buffer(buffer_id, cx);
17438                            } else {
17439                                editor.fold_buffer(buffer_id, cx);
17440                            }
17441                        }
17442                    })
17443                    .ok();
17444            });
17445        }
17446    }
17447
17448    fn fold_at_level(
17449        &mut self,
17450        fold_at: &FoldAtLevel,
17451        window: &mut Window,
17452        cx: &mut Context<Self>,
17453    ) {
17454        if !self.buffer.read(cx).is_singleton() {
17455            return;
17456        }
17457
17458        let fold_at_level = fold_at.0;
17459        let snapshot = self.buffer.read(cx).snapshot(cx);
17460        let mut to_fold = Vec::new();
17461        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17462
17463        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17464            while start_row < end_row {
17465                match self
17466                    .snapshot(window, cx)
17467                    .crease_for_buffer_row(MultiBufferRow(start_row))
17468                {
17469                    Some(crease) => {
17470                        let nested_start_row = crease.range().start.row + 1;
17471                        let nested_end_row = crease.range().end.row;
17472
17473                        if current_level < fold_at_level {
17474                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17475                        } else if current_level == fold_at_level {
17476                            to_fold.push(crease);
17477                        }
17478
17479                        start_row = nested_end_row + 1;
17480                    }
17481                    None => start_row += 1,
17482                }
17483            }
17484        }
17485
17486        self.fold_creases(to_fold, true, window, cx);
17487    }
17488
17489    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17490        if self.buffer.read(cx).is_singleton() {
17491            let mut fold_ranges = Vec::new();
17492            let snapshot = self.buffer.read(cx).snapshot(cx);
17493
17494            for row in 0..snapshot.max_row().0 {
17495                if let Some(foldable_range) = self
17496                    .snapshot(window, cx)
17497                    .crease_for_buffer_row(MultiBufferRow(row))
17498                {
17499                    fold_ranges.push(foldable_range);
17500                }
17501            }
17502
17503            self.fold_creases(fold_ranges, true, window, cx);
17504        } else {
17505            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17506                editor
17507                    .update_in(cx, |editor, _, cx| {
17508                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17509                            editor.fold_buffer(buffer_id, cx);
17510                        }
17511                    })
17512                    .ok();
17513            });
17514        }
17515    }
17516
17517    pub fn fold_function_bodies(
17518        &mut self,
17519        _: &actions::FoldFunctionBodies,
17520        window: &mut Window,
17521        cx: &mut Context<Self>,
17522    ) {
17523        let snapshot = self.buffer.read(cx).snapshot(cx);
17524
17525        let ranges = snapshot
17526            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17527            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17528            .collect::<Vec<_>>();
17529
17530        let creases = ranges
17531            .into_iter()
17532            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17533            .collect();
17534
17535        self.fold_creases(creases, true, window, cx);
17536    }
17537
17538    pub fn fold_recursive(
17539        &mut self,
17540        _: &actions::FoldRecursive,
17541        window: &mut Window,
17542        cx: &mut Context<Self>,
17543    ) {
17544        let mut to_fold = Vec::new();
17545        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17546        let selections = self.selections.all_adjusted(cx);
17547
17548        for selection in selections {
17549            let range = selection.range().sorted();
17550            let buffer_start_row = range.start.row;
17551
17552            if range.start.row != range.end.row {
17553                let mut found = false;
17554                for row in range.start.row..=range.end.row {
17555                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17556                        found = true;
17557                        to_fold.push(crease);
17558                    }
17559                }
17560                if found {
17561                    continue;
17562                }
17563            }
17564
17565            for row in (0..=range.start.row).rev() {
17566                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17567                    if crease.range().end.row >= buffer_start_row {
17568                        to_fold.push(crease);
17569                    } else {
17570                        break;
17571                    }
17572                }
17573            }
17574        }
17575
17576        self.fold_creases(to_fold, true, window, cx);
17577    }
17578
17579    pub fn fold_at(
17580        &mut self,
17581        buffer_row: MultiBufferRow,
17582        window: &mut Window,
17583        cx: &mut Context<Self>,
17584    ) {
17585        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17586
17587        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17588            let autoscroll = self
17589                .selections
17590                .all::<Point>(cx)
17591                .iter()
17592                .any(|selection| crease.range().overlaps(&selection.range()));
17593
17594            self.fold_creases(vec![crease], autoscroll, window, cx);
17595        }
17596    }
17597
17598    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17599        if self.is_singleton(cx) {
17600            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17601            let buffer = &display_map.buffer_snapshot;
17602            let selections = self.selections.all::<Point>(cx);
17603            let ranges = selections
17604                .iter()
17605                .map(|s| {
17606                    let range = s.display_range(&display_map).sorted();
17607                    let mut start = range.start.to_point(&display_map);
17608                    let mut end = range.end.to_point(&display_map);
17609                    start.column = 0;
17610                    end.column = buffer.line_len(MultiBufferRow(end.row));
17611                    start..end
17612                })
17613                .collect::<Vec<_>>();
17614
17615            self.unfold_ranges(&ranges, true, true, cx);
17616        } else {
17617            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17618            let buffer_ids = self
17619                .selections
17620                .disjoint_anchor_ranges()
17621                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17622                .collect::<HashSet<_>>();
17623            for buffer_id in buffer_ids {
17624                self.unfold_buffer(buffer_id, cx);
17625            }
17626        }
17627    }
17628
17629    pub fn unfold_recursive(
17630        &mut self,
17631        _: &UnfoldRecursive,
17632        _window: &mut Window,
17633        cx: &mut Context<Self>,
17634    ) {
17635        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17636        let selections = self.selections.all::<Point>(cx);
17637        let ranges = selections
17638            .iter()
17639            .map(|s| {
17640                let mut range = s.display_range(&display_map).sorted();
17641                *range.start.column_mut() = 0;
17642                *range.end.column_mut() = display_map.line_len(range.end.row());
17643                let start = range.start.to_point(&display_map);
17644                let end = range.end.to_point(&display_map);
17645                start..end
17646            })
17647            .collect::<Vec<_>>();
17648
17649        self.unfold_ranges(&ranges, true, true, cx);
17650    }
17651
17652    pub fn unfold_at(
17653        &mut self,
17654        buffer_row: MultiBufferRow,
17655        _window: &mut Window,
17656        cx: &mut Context<Self>,
17657    ) {
17658        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17659
17660        let intersection_range = Point::new(buffer_row.0, 0)
17661            ..Point::new(
17662                buffer_row.0,
17663                display_map.buffer_snapshot.line_len(buffer_row),
17664            );
17665
17666        let autoscroll = self
17667            .selections
17668            .all::<Point>(cx)
17669            .iter()
17670            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17671
17672        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17673    }
17674
17675    pub fn unfold_all(
17676        &mut self,
17677        _: &actions::UnfoldAll,
17678        _window: &mut Window,
17679        cx: &mut Context<Self>,
17680    ) {
17681        if self.buffer.read(cx).is_singleton() {
17682            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17683            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17684        } else {
17685            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17686                editor
17687                    .update(cx, |editor, cx| {
17688                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17689                            editor.unfold_buffer(buffer_id, cx);
17690                        }
17691                    })
17692                    .ok();
17693            });
17694        }
17695    }
17696
17697    pub fn fold_selected_ranges(
17698        &mut self,
17699        _: &FoldSelectedRanges,
17700        window: &mut Window,
17701        cx: &mut Context<Self>,
17702    ) {
17703        let selections = self.selections.all_adjusted(cx);
17704        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17705        let ranges = selections
17706            .into_iter()
17707            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17708            .collect::<Vec<_>>();
17709        self.fold_creases(ranges, true, window, cx);
17710    }
17711
17712    pub fn fold_ranges<T: ToOffset + Clone>(
17713        &mut self,
17714        ranges: Vec<Range<T>>,
17715        auto_scroll: bool,
17716        window: &mut Window,
17717        cx: &mut Context<Self>,
17718    ) {
17719        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17720        let ranges = ranges
17721            .into_iter()
17722            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17723            .collect::<Vec<_>>();
17724        self.fold_creases(ranges, auto_scroll, window, cx);
17725    }
17726
17727    pub fn fold_creases<T: ToOffset + Clone>(
17728        &mut self,
17729        creases: Vec<Crease<T>>,
17730        auto_scroll: bool,
17731        _window: &mut Window,
17732        cx: &mut Context<Self>,
17733    ) {
17734        if creases.is_empty() {
17735            return;
17736        }
17737
17738        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17739
17740        if auto_scroll {
17741            self.request_autoscroll(Autoscroll::fit(), cx);
17742        }
17743
17744        cx.notify();
17745
17746        self.scrollbar_marker_state.dirty = true;
17747        self.folds_did_change(cx);
17748    }
17749
17750    /// Removes any folds whose ranges intersect any of the given ranges.
17751    pub fn unfold_ranges<T: ToOffset + Clone>(
17752        &mut self,
17753        ranges: &[Range<T>],
17754        inclusive: bool,
17755        auto_scroll: bool,
17756        cx: &mut Context<Self>,
17757    ) {
17758        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17759            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17760        });
17761        self.folds_did_change(cx);
17762    }
17763
17764    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17765        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17766            return;
17767        }
17768        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17769        self.display_map.update(cx, |display_map, cx| {
17770            display_map.fold_buffers([buffer_id], cx)
17771        });
17772        cx.emit(EditorEvent::BufferFoldToggled {
17773            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17774            folded: true,
17775        });
17776        cx.notify();
17777    }
17778
17779    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17780        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17781            return;
17782        }
17783        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17784        self.display_map.update(cx, |display_map, cx| {
17785            display_map.unfold_buffers([buffer_id], cx);
17786        });
17787        cx.emit(EditorEvent::BufferFoldToggled {
17788            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17789            folded: false,
17790        });
17791        cx.notify();
17792    }
17793
17794    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17795        self.display_map.read(cx).is_buffer_folded(buffer)
17796    }
17797
17798    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17799        self.display_map.read(cx).folded_buffers()
17800    }
17801
17802    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17803        self.display_map.update(cx, |display_map, cx| {
17804            display_map.disable_header_for_buffer(buffer_id, cx);
17805        });
17806        cx.notify();
17807    }
17808
17809    /// Removes any folds with the given ranges.
17810    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17811        &mut self,
17812        ranges: &[Range<T>],
17813        type_id: TypeId,
17814        auto_scroll: bool,
17815        cx: &mut Context<Self>,
17816    ) {
17817        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17818            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17819        });
17820        self.folds_did_change(cx);
17821    }
17822
17823    fn remove_folds_with<T: ToOffset + Clone>(
17824        &mut self,
17825        ranges: &[Range<T>],
17826        auto_scroll: bool,
17827        cx: &mut Context<Self>,
17828        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17829    ) {
17830        if ranges.is_empty() {
17831            return;
17832        }
17833
17834        let mut buffers_affected = HashSet::default();
17835        let multi_buffer = self.buffer().read(cx);
17836        for range in ranges {
17837            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17838                buffers_affected.insert(buffer.read(cx).remote_id());
17839            };
17840        }
17841
17842        self.display_map.update(cx, update);
17843
17844        if auto_scroll {
17845            self.request_autoscroll(Autoscroll::fit(), cx);
17846        }
17847
17848        cx.notify();
17849        self.scrollbar_marker_state.dirty = true;
17850        self.active_indent_guides_state.dirty = true;
17851    }
17852
17853    pub fn update_renderer_widths(
17854        &mut self,
17855        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17856        cx: &mut Context<Self>,
17857    ) -> bool {
17858        self.display_map
17859            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17860    }
17861
17862    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17863        self.display_map.read(cx).fold_placeholder.clone()
17864    }
17865
17866    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17867        self.buffer.update(cx, |buffer, cx| {
17868            buffer.set_all_diff_hunks_expanded(cx);
17869        });
17870    }
17871
17872    pub fn expand_all_diff_hunks(
17873        &mut self,
17874        _: &ExpandAllDiffHunks,
17875        _window: &mut Window,
17876        cx: &mut Context<Self>,
17877    ) {
17878        self.buffer.update(cx, |buffer, cx| {
17879            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17880        });
17881    }
17882
17883    pub fn toggle_selected_diff_hunks(
17884        &mut self,
17885        _: &ToggleSelectedDiffHunks,
17886        _window: &mut Window,
17887        cx: &mut Context<Self>,
17888    ) {
17889        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17890        self.toggle_diff_hunks_in_ranges(ranges, cx);
17891    }
17892
17893    pub fn diff_hunks_in_ranges<'a>(
17894        &'a self,
17895        ranges: &'a [Range<Anchor>],
17896        buffer: &'a MultiBufferSnapshot,
17897    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17898        ranges.iter().flat_map(move |range| {
17899            let end_excerpt_id = range.end.excerpt_id;
17900            let range = range.to_point(buffer);
17901            let mut peek_end = range.end;
17902            if range.end.row < buffer.max_row().0 {
17903                peek_end = Point::new(range.end.row + 1, 0);
17904            }
17905            buffer
17906                .diff_hunks_in_range(range.start..peek_end)
17907                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17908        })
17909    }
17910
17911    pub fn has_stageable_diff_hunks_in_ranges(
17912        &self,
17913        ranges: &[Range<Anchor>],
17914        snapshot: &MultiBufferSnapshot,
17915    ) -> bool {
17916        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17917        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17918    }
17919
17920    pub fn toggle_staged_selected_diff_hunks(
17921        &mut self,
17922        _: &::git::ToggleStaged,
17923        _: &mut Window,
17924        cx: &mut Context<Self>,
17925    ) {
17926        let snapshot = self.buffer.read(cx).snapshot(cx);
17927        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17928        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17929        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17930    }
17931
17932    pub fn set_render_diff_hunk_controls(
17933        &mut self,
17934        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17935        cx: &mut Context<Self>,
17936    ) {
17937        self.render_diff_hunk_controls = render_diff_hunk_controls;
17938        cx.notify();
17939    }
17940
17941    pub fn stage_and_next(
17942        &mut self,
17943        _: &::git::StageAndNext,
17944        window: &mut Window,
17945        cx: &mut Context<Self>,
17946    ) {
17947        self.do_stage_or_unstage_and_next(true, window, cx);
17948    }
17949
17950    pub fn unstage_and_next(
17951        &mut self,
17952        _: &::git::UnstageAndNext,
17953        window: &mut Window,
17954        cx: &mut Context<Self>,
17955    ) {
17956        self.do_stage_or_unstage_and_next(false, window, cx);
17957    }
17958
17959    pub fn stage_or_unstage_diff_hunks(
17960        &mut self,
17961        stage: bool,
17962        ranges: Vec<Range<Anchor>>,
17963        cx: &mut Context<Self>,
17964    ) {
17965        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17966        cx.spawn(async move |this, cx| {
17967            task.await?;
17968            this.update(cx, |this, cx| {
17969                let snapshot = this.buffer.read(cx).snapshot(cx);
17970                let chunk_by = this
17971                    .diff_hunks_in_ranges(&ranges, &snapshot)
17972                    .chunk_by(|hunk| hunk.buffer_id);
17973                for (buffer_id, hunks) in &chunk_by {
17974                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17975                }
17976            })
17977        })
17978        .detach_and_log_err(cx);
17979    }
17980
17981    fn save_buffers_for_ranges_if_needed(
17982        &mut self,
17983        ranges: &[Range<Anchor>],
17984        cx: &mut Context<Editor>,
17985    ) -> Task<Result<()>> {
17986        let multibuffer = self.buffer.read(cx);
17987        let snapshot = multibuffer.read(cx);
17988        let buffer_ids: HashSet<_> = ranges
17989            .iter()
17990            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17991            .collect();
17992        drop(snapshot);
17993
17994        let mut buffers = HashSet::default();
17995        for buffer_id in buffer_ids {
17996            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17997                let buffer = buffer_entity.read(cx);
17998                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17999                {
18000                    buffers.insert(buffer_entity);
18001                }
18002            }
18003        }
18004
18005        if let Some(project) = &self.project {
18006            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18007        } else {
18008            Task::ready(Ok(()))
18009        }
18010    }
18011
18012    fn do_stage_or_unstage_and_next(
18013        &mut self,
18014        stage: bool,
18015        window: &mut Window,
18016        cx: &mut Context<Self>,
18017    ) {
18018        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18019
18020        if ranges.iter().any(|range| range.start != range.end) {
18021            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18022            return;
18023        }
18024
18025        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18026        let snapshot = self.snapshot(window, cx);
18027        let position = self.selections.newest::<Point>(cx).head();
18028        let mut row = snapshot
18029            .buffer_snapshot
18030            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18031            .find(|hunk| hunk.row_range.start.0 > position.row)
18032            .map(|hunk| hunk.row_range.start);
18033
18034        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18035        // Outside of the project diff editor, wrap around to the beginning.
18036        if !all_diff_hunks_expanded {
18037            row = row.or_else(|| {
18038                snapshot
18039                    .buffer_snapshot
18040                    .diff_hunks_in_range(Point::zero()..position)
18041                    .find(|hunk| hunk.row_range.end.0 < position.row)
18042                    .map(|hunk| hunk.row_range.start)
18043            });
18044        }
18045
18046        if let Some(row) = row {
18047            let destination = Point::new(row.0, 0);
18048            let autoscroll = Autoscroll::center();
18049
18050            self.unfold_ranges(&[destination..destination], false, false, cx);
18051            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18052                s.select_ranges([destination..destination]);
18053            });
18054        }
18055    }
18056
18057    fn do_stage_or_unstage(
18058        &self,
18059        stage: bool,
18060        buffer_id: BufferId,
18061        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18062        cx: &mut App,
18063    ) -> Option<()> {
18064        let project = self.project()?;
18065        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18066        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18067        let buffer_snapshot = buffer.read(cx).snapshot();
18068        let file_exists = buffer_snapshot
18069            .file()
18070            .is_some_and(|file| file.disk_state().exists());
18071        diff.update(cx, |diff, cx| {
18072            diff.stage_or_unstage_hunks(
18073                stage,
18074                &hunks
18075                    .map(|hunk| buffer_diff::DiffHunk {
18076                        buffer_range: hunk.buffer_range,
18077                        diff_base_byte_range: hunk.diff_base_byte_range,
18078                        secondary_status: hunk.secondary_status,
18079                        range: Point::zero()..Point::zero(), // unused
18080                    })
18081                    .collect::<Vec<_>>(),
18082                &buffer_snapshot,
18083                file_exists,
18084                cx,
18085            )
18086        });
18087        None
18088    }
18089
18090    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18091        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18092        self.buffer
18093            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18094    }
18095
18096    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18097        self.buffer.update(cx, |buffer, cx| {
18098            let ranges = vec![Anchor::min()..Anchor::max()];
18099            if !buffer.all_diff_hunks_expanded()
18100                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18101            {
18102                buffer.collapse_diff_hunks(ranges, cx);
18103                true
18104            } else {
18105                false
18106            }
18107        })
18108    }
18109
18110    fn toggle_diff_hunks_in_ranges(
18111        &mut self,
18112        ranges: Vec<Range<Anchor>>,
18113        cx: &mut Context<Editor>,
18114    ) {
18115        self.buffer.update(cx, |buffer, cx| {
18116            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18117            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18118        })
18119    }
18120
18121    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18122        self.buffer.update(cx, |buffer, cx| {
18123            let snapshot = buffer.snapshot(cx);
18124            let excerpt_id = range.end.excerpt_id;
18125            let point_range = range.to_point(&snapshot);
18126            let expand = !buffer.single_hunk_is_expanded(range, cx);
18127            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18128        })
18129    }
18130
18131    pub(crate) fn apply_all_diff_hunks(
18132        &mut self,
18133        _: &ApplyAllDiffHunks,
18134        window: &mut Window,
18135        cx: &mut Context<Self>,
18136    ) {
18137        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18138
18139        let buffers = self.buffer.read(cx).all_buffers();
18140        for branch_buffer in buffers {
18141            branch_buffer.update(cx, |branch_buffer, cx| {
18142                branch_buffer.merge_into_base(Vec::new(), cx);
18143            });
18144        }
18145
18146        if let Some(project) = self.project.clone() {
18147            self.save(
18148                SaveOptions {
18149                    format: true,
18150                    autosave: false,
18151                },
18152                project,
18153                window,
18154                cx,
18155            )
18156            .detach_and_log_err(cx);
18157        }
18158    }
18159
18160    pub(crate) fn apply_selected_diff_hunks(
18161        &mut self,
18162        _: &ApplyDiffHunk,
18163        window: &mut Window,
18164        cx: &mut Context<Self>,
18165    ) {
18166        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18167        let snapshot = self.snapshot(window, cx);
18168        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18169        let mut ranges_by_buffer = HashMap::default();
18170        self.transact(window, cx, |editor, _window, cx| {
18171            for hunk in hunks {
18172                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18173                    ranges_by_buffer
18174                        .entry(buffer.clone())
18175                        .or_insert_with(Vec::new)
18176                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18177                }
18178            }
18179
18180            for (buffer, ranges) in ranges_by_buffer {
18181                buffer.update(cx, |buffer, cx| {
18182                    buffer.merge_into_base(ranges, cx);
18183                });
18184            }
18185        });
18186
18187        if let Some(project) = self.project.clone() {
18188            self.save(
18189                SaveOptions {
18190                    format: true,
18191                    autosave: false,
18192                },
18193                project,
18194                window,
18195                cx,
18196            )
18197            .detach_and_log_err(cx);
18198        }
18199    }
18200
18201    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18202        if hovered != self.gutter_hovered {
18203            self.gutter_hovered = hovered;
18204            cx.notify();
18205        }
18206    }
18207
18208    pub fn insert_blocks(
18209        &mut self,
18210        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18211        autoscroll: Option<Autoscroll>,
18212        cx: &mut Context<Self>,
18213    ) -> Vec<CustomBlockId> {
18214        let blocks = self
18215            .display_map
18216            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18217        if let Some(autoscroll) = autoscroll {
18218            self.request_autoscroll(autoscroll, cx);
18219        }
18220        cx.notify();
18221        blocks
18222    }
18223
18224    pub fn resize_blocks(
18225        &mut self,
18226        heights: HashMap<CustomBlockId, u32>,
18227        autoscroll: Option<Autoscroll>,
18228        cx: &mut Context<Self>,
18229    ) {
18230        self.display_map
18231            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18232        if let Some(autoscroll) = autoscroll {
18233            self.request_autoscroll(autoscroll, cx);
18234        }
18235        cx.notify();
18236    }
18237
18238    pub fn replace_blocks(
18239        &mut self,
18240        renderers: HashMap<CustomBlockId, RenderBlock>,
18241        autoscroll: Option<Autoscroll>,
18242        cx: &mut Context<Self>,
18243    ) {
18244        self.display_map
18245            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18246        if let Some(autoscroll) = autoscroll {
18247            self.request_autoscroll(autoscroll, cx);
18248        }
18249        cx.notify();
18250    }
18251
18252    pub fn remove_blocks(
18253        &mut self,
18254        block_ids: HashSet<CustomBlockId>,
18255        autoscroll: Option<Autoscroll>,
18256        cx: &mut Context<Self>,
18257    ) {
18258        self.display_map.update(cx, |display_map, cx| {
18259            display_map.remove_blocks(block_ids, cx)
18260        });
18261        if let Some(autoscroll) = autoscroll {
18262            self.request_autoscroll(autoscroll, cx);
18263        }
18264        cx.notify();
18265    }
18266
18267    pub fn row_for_block(
18268        &self,
18269        block_id: CustomBlockId,
18270        cx: &mut Context<Self>,
18271    ) -> Option<DisplayRow> {
18272        self.display_map
18273            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18274    }
18275
18276    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18277        self.focused_block = Some(focused_block);
18278    }
18279
18280    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18281        self.focused_block.take()
18282    }
18283
18284    pub fn insert_creases(
18285        &mut self,
18286        creases: impl IntoIterator<Item = Crease<Anchor>>,
18287        cx: &mut Context<Self>,
18288    ) -> Vec<CreaseId> {
18289        self.display_map
18290            .update(cx, |map, cx| map.insert_creases(creases, cx))
18291    }
18292
18293    pub fn remove_creases(
18294        &mut self,
18295        ids: impl IntoIterator<Item = CreaseId>,
18296        cx: &mut Context<Self>,
18297    ) -> Vec<(CreaseId, Range<Anchor>)> {
18298        self.display_map
18299            .update(cx, |map, cx| map.remove_creases(ids, cx))
18300    }
18301
18302    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18303        self.display_map
18304            .update(cx, |map, cx| map.snapshot(cx))
18305            .longest_row()
18306    }
18307
18308    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18309        self.display_map
18310            .update(cx, |map, cx| map.snapshot(cx))
18311            .max_point()
18312    }
18313
18314    pub fn text(&self, cx: &App) -> String {
18315        self.buffer.read(cx).read(cx).text()
18316    }
18317
18318    pub fn is_empty(&self, cx: &App) -> bool {
18319        self.buffer.read(cx).read(cx).is_empty()
18320    }
18321
18322    pub fn text_option(&self, cx: &App) -> Option<String> {
18323        let text = self.text(cx);
18324        let text = text.trim();
18325
18326        if text.is_empty() {
18327            return None;
18328        }
18329
18330        Some(text.to_string())
18331    }
18332
18333    pub fn set_text(
18334        &mut self,
18335        text: impl Into<Arc<str>>,
18336        window: &mut Window,
18337        cx: &mut Context<Self>,
18338    ) {
18339        self.transact(window, cx, |this, _, cx| {
18340            this.buffer
18341                .read(cx)
18342                .as_singleton()
18343                .expect("you can only call set_text on editors for singleton buffers")
18344                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18345        });
18346    }
18347
18348    pub fn display_text(&self, cx: &mut App) -> String {
18349        self.display_map
18350            .update(cx, |map, cx| map.snapshot(cx))
18351            .text()
18352    }
18353
18354    fn create_minimap(
18355        &self,
18356        minimap_settings: MinimapSettings,
18357        window: &mut Window,
18358        cx: &mut Context<Self>,
18359    ) -> Option<Entity<Self>> {
18360        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18361            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18362    }
18363
18364    fn initialize_new_minimap(
18365        &self,
18366        minimap_settings: MinimapSettings,
18367        window: &mut Window,
18368        cx: &mut Context<Self>,
18369    ) -> Entity<Self> {
18370        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18371
18372        let mut minimap = Editor::new_internal(
18373            EditorMode::Minimap {
18374                parent: cx.weak_entity(),
18375            },
18376            self.buffer.clone(),
18377            None,
18378            Some(self.display_map.clone()),
18379            window,
18380            cx,
18381        );
18382        minimap.scroll_manager.clone_state(&self.scroll_manager);
18383        minimap.set_text_style_refinement(TextStyleRefinement {
18384            font_size: Some(MINIMAP_FONT_SIZE),
18385            font_weight: Some(MINIMAP_FONT_WEIGHT),
18386            ..Default::default()
18387        });
18388        minimap.update_minimap_configuration(minimap_settings, cx);
18389        cx.new(|_| minimap)
18390    }
18391
18392    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18393        let current_line_highlight = minimap_settings
18394            .current_line_highlight
18395            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18396        self.set_current_line_highlight(Some(current_line_highlight));
18397    }
18398
18399    pub fn minimap(&self) -> Option<&Entity<Self>> {
18400        self.minimap
18401            .as_ref()
18402            .filter(|_| self.minimap_visibility.visible())
18403    }
18404
18405    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18406        let mut wrap_guides = smallvec![];
18407
18408        if self.show_wrap_guides == Some(false) {
18409            return wrap_guides;
18410        }
18411
18412        let settings = self.buffer.read(cx).language_settings(cx);
18413        if settings.show_wrap_guides {
18414            match self.soft_wrap_mode(cx) {
18415                SoftWrap::Column(soft_wrap) => {
18416                    wrap_guides.push((soft_wrap as usize, true));
18417                }
18418                SoftWrap::Bounded(soft_wrap) => {
18419                    wrap_guides.push((soft_wrap as usize, true));
18420                }
18421                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18422            }
18423            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18424        }
18425
18426        wrap_guides
18427    }
18428
18429    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18430        let settings = self.buffer.read(cx).language_settings(cx);
18431        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18432        match mode {
18433            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18434                SoftWrap::None
18435            }
18436            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18437            language_settings::SoftWrap::PreferredLineLength => {
18438                SoftWrap::Column(settings.preferred_line_length)
18439            }
18440            language_settings::SoftWrap::Bounded => {
18441                SoftWrap::Bounded(settings.preferred_line_length)
18442            }
18443        }
18444    }
18445
18446    pub fn set_soft_wrap_mode(
18447        &mut self,
18448        mode: language_settings::SoftWrap,
18449
18450        cx: &mut Context<Self>,
18451    ) {
18452        self.soft_wrap_mode_override = Some(mode);
18453        cx.notify();
18454    }
18455
18456    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18457        self.hard_wrap = hard_wrap;
18458        cx.notify();
18459    }
18460
18461    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18462        self.text_style_refinement = Some(style);
18463    }
18464
18465    /// called by the Element so we know what style we were most recently rendered with.
18466    pub(crate) fn set_style(
18467        &mut self,
18468        style: EditorStyle,
18469        window: &mut Window,
18470        cx: &mut Context<Self>,
18471    ) {
18472        // We intentionally do not inform the display map about the minimap style
18473        // so that wrapping is not recalculated and stays consistent for the editor
18474        // and its linked minimap.
18475        if !self.mode.is_minimap() {
18476            let rem_size = window.rem_size();
18477            self.display_map.update(cx, |map, cx| {
18478                map.set_font(
18479                    style.text.font(),
18480                    style.text.font_size.to_pixels(rem_size),
18481                    cx,
18482                )
18483            });
18484        }
18485        self.style = Some(style);
18486    }
18487
18488    pub fn style(&self) -> Option<&EditorStyle> {
18489        self.style.as_ref()
18490    }
18491
18492    // Called by the element. This method is not designed to be called outside of the editor
18493    // element's layout code because it does not notify when rewrapping is computed synchronously.
18494    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18495        self.display_map
18496            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18497    }
18498
18499    pub fn set_soft_wrap(&mut self) {
18500        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18501    }
18502
18503    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18504        if self.soft_wrap_mode_override.is_some() {
18505            self.soft_wrap_mode_override.take();
18506        } else {
18507            let soft_wrap = match self.soft_wrap_mode(cx) {
18508                SoftWrap::GitDiff => return,
18509                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18510                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18511                    language_settings::SoftWrap::None
18512                }
18513            };
18514            self.soft_wrap_mode_override = Some(soft_wrap);
18515        }
18516        cx.notify();
18517    }
18518
18519    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18520        let Some(workspace) = self.workspace() else {
18521            return;
18522        };
18523        let fs = workspace.read(cx).app_state().fs.clone();
18524        let current_show = TabBarSettings::get_global(cx).show;
18525        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18526            setting.show = Some(!current_show);
18527        });
18528    }
18529
18530    pub fn toggle_indent_guides(
18531        &mut self,
18532        _: &ToggleIndentGuides,
18533        _: &mut Window,
18534        cx: &mut Context<Self>,
18535    ) {
18536        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18537            self.buffer
18538                .read(cx)
18539                .language_settings(cx)
18540                .indent_guides
18541                .enabled
18542        });
18543        self.show_indent_guides = Some(!currently_enabled);
18544        cx.notify();
18545    }
18546
18547    fn should_show_indent_guides(&self) -> Option<bool> {
18548        self.show_indent_guides
18549    }
18550
18551    pub fn toggle_line_numbers(
18552        &mut self,
18553        _: &ToggleLineNumbers,
18554        _: &mut Window,
18555        cx: &mut Context<Self>,
18556    ) {
18557        let mut editor_settings = EditorSettings::get_global(cx).clone();
18558        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18559        EditorSettings::override_global(editor_settings, cx);
18560    }
18561
18562    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18563        if let Some(show_line_numbers) = self.show_line_numbers {
18564            return show_line_numbers;
18565        }
18566        EditorSettings::get_global(cx).gutter.line_numbers
18567    }
18568
18569    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18570        self.use_relative_line_numbers
18571            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18572    }
18573
18574    pub fn toggle_relative_line_numbers(
18575        &mut self,
18576        _: &ToggleRelativeLineNumbers,
18577        _: &mut Window,
18578        cx: &mut Context<Self>,
18579    ) {
18580        let is_relative = self.should_use_relative_line_numbers(cx);
18581        self.set_relative_line_number(Some(!is_relative), cx)
18582    }
18583
18584    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18585        self.use_relative_line_numbers = is_relative;
18586        cx.notify();
18587    }
18588
18589    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18590        self.show_gutter = show_gutter;
18591        cx.notify();
18592    }
18593
18594    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18595        self.show_scrollbars = ScrollbarAxes {
18596            horizontal: show,
18597            vertical: show,
18598        };
18599        cx.notify();
18600    }
18601
18602    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18603        self.show_scrollbars.vertical = show;
18604        cx.notify();
18605    }
18606
18607    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18608        self.show_scrollbars.horizontal = show;
18609        cx.notify();
18610    }
18611
18612    pub fn set_minimap_visibility(
18613        &mut self,
18614        minimap_visibility: MinimapVisibility,
18615        window: &mut Window,
18616        cx: &mut Context<Self>,
18617    ) {
18618        if self.minimap_visibility != minimap_visibility {
18619            if minimap_visibility.visible() && self.minimap.is_none() {
18620                let minimap_settings = EditorSettings::get_global(cx).minimap;
18621                self.minimap =
18622                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18623            }
18624            self.minimap_visibility = minimap_visibility;
18625            cx.notify();
18626        }
18627    }
18628
18629    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18630        self.set_show_scrollbars(false, cx);
18631        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18632    }
18633
18634    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18635        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18636    }
18637
18638    /// Normally the text in full mode and auto height editors is padded on the
18639    /// left side by roughly half a character width for improved hit testing.
18640    ///
18641    /// Use this method to disable this for cases where this is not wanted (e.g.
18642    /// if you want to align the editor text with some other text above or below)
18643    /// or if you want to add this padding to single-line editors.
18644    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18645        self.offset_content = offset_content;
18646        cx.notify();
18647    }
18648
18649    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18650        self.show_line_numbers = Some(show_line_numbers);
18651        cx.notify();
18652    }
18653
18654    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18655        self.disable_expand_excerpt_buttons = true;
18656        cx.notify();
18657    }
18658
18659    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18660        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18661        cx.notify();
18662    }
18663
18664    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18665        self.show_code_actions = Some(show_code_actions);
18666        cx.notify();
18667    }
18668
18669    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18670        self.show_runnables = Some(show_runnables);
18671        cx.notify();
18672    }
18673
18674    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18675        self.show_breakpoints = Some(show_breakpoints);
18676        cx.notify();
18677    }
18678
18679    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18680        if self.display_map.read(cx).masked != masked {
18681            self.display_map.update(cx, |map, _| map.masked = masked);
18682        }
18683        cx.notify()
18684    }
18685
18686    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18687        self.show_wrap_guides = Some(show_wrap_guides);
18688        cx.notify();
18689    }
18690
18691    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18692        self.show_indent_guides = Some(show_indent_guides);
18693        cx.notify();
18694    }
18695
18696    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18697        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18698            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18699                && let Some(dir) = file.abs_path(cx).parent()
18700            {
18701                return Some(dir.to_owned());
18702            }
18703
18704            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18705                return Some(project_path.path.to_path_buf());
18706            }
18707        }
18708
18709        None
18710    }
18711
18712    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18713        self.active_excerpt(cx)?
18714            .1
18715            .read(cx)
18716            .file()
18717            .and_then(|f| f.as_local())
18718    }
18719
18720    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18721        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18722            let buffer = buffer.read(cx);
18723            if let Some(project_path) = buffer.project_path(cx) {
18724                let project = self.project()?.read(cx);
18725                project.absolute_path(&project_path, cx)
18726            } else {
18727                buffer
18728                    .file()
18729                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18730            }
18731        })
18732    }
18733
18734    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18735        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18736            let project_path = buffer.read(cx).project_path(cx)?;
18737            let project = self.project()?.read(cx);
18738            let entry = project.entry_for_path(&project_path, cx)?;
18739            let path = entry.path.to_path_buf();
18740            Some(path)
18741        })
18742    }
18743
18744    pub fn reveal_in_finder(
18745        &mut self,
18746        _: &RevealInFileManager,
18747        _window: &mut Window,
18748        cx: &mut Context<Self>,
18749    ) {
18750        if let Some(target) = self.target_file(cx) {
18751            cx.reveal_path(&target.abs_path(cx));
18752        }
18753    }
18754
18755    pub fn copy_path(
18756        &mut self,
18757        _: &zed_actions::workspace::CopyPath,
18758        _window: &mut Window,
18759        cx: &mut Context<Self>,
18760    ) {
18761        if let Some(path) = self.target_file_abs_path(cx)
18762            && let Some(path) = path.to_str()
18763        {
18764            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18765        }
18766    }
18767
18768    pub fn copy_relative_path(
18769        &mut self,
18770        _: &zed_actions::workspace::CopyRelativePath,
18771        _window: &mut Window,
18772        cx: &mut Context<Self>,
18773    ) {
18774        if let Some(path) = self.target_file_path(cx)
18775            && let Some(path) = path.to_str()
18776        {
18777            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18778        }
18779    }
18780
18781    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18782        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18783            buffer.read(cx).project_path(cx)
18784        } else {
18785            None
18786        }
18787    }
18788
18789    // Returns true if the editor handled a go-to-line request
18790    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18791        maybe!({
18792            let breakpoint_store = self.breakpoint_store.as_ref()?;
18793
18794            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18795            else {
18796                self.clear_row_highlights::<ActiveDebugLine>();
18797                return None;
18798            };
18799
18800            let position = active_stack_frame.position;
18801            let buffer_id = position.buffer_id?;
18802            let snapshot = self
18803                .project
18804                .as_ref()?
18805                .read(cx)
18806                .buffer_for_id(buffer_id, cx)?
18807                .read(cx)
18808                .snapshot();
18809
18810            let mut handled = false;
18811            for (id, ExcerptRange { context, .. }) in
18812                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18813            {
18814                if context.start.cmp(&position, &snapshot).is_ge()
18815                    || context.end.cmp(&position, &snapshot).is_lt()
18816                {
18817                    continue;
18818                }
18819                let snapshot = self.buffer.read(cx).snapshot(cx);
18820                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18821
18822                handled = true;
18823                self.clear_row_highlights::<ActiveDebugLine>();
18824
18825                self.go_to_line::<ActiveDebugLine>(
18826                    multibuffer_anchor,
18827                    Some(cx.theme().colors().editor_debugger_active_line_background),
18828                    window,
18829                    cx,
18830                );
18831
18832                cx.notify();
18833            }
18834
18835            handled.then_some(())
18836        })
18837        .is_some()
18838    }
18839
18840    pub fn copy_file_name_without_extension(
18841        &mut self,
18842        _: &CopyFileNameWithoutExtension,
18843        _: &mut Window,
18844        cx: &mut Context<Self>,
18845    ) {
18846        if let Some(file) = self.target_file(cx)
18847            && let Some(file_stem) = file.path().file_stem()
18848            && let Some(name) = file_stem.to_str()
18849        {
18850            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18851        }
18852    }
18853
18854    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18855        if let Some(file) = self.target_file(cx)
18856            && let Some(file_name) = file.path().file_name()
18857            && let Some(name) = file_name.to_str()
18858        {
18859            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18860        }
18861    }
18862
18863    pub fn toggle_git_blame(
18864        &mut self,
18865        _: &::git::Blame,
18866        window: &mut Window,
18867        cx: &mut Context<Self>,
18868    ) {
18869        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18870
18871        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18872            self.start_git_blame(true, window, cx);
18873        }
18874
18875        cx.notify();
18876    }
18877
18878    pub fn toggle_git_blame_inline(
18879        &mut self,
18880        _: &ToggleGitBlameInline,
18881        window: &mut Window,
18882        cx: &mut Context<Self>,
18883    ) {
18884        self.toggle_git_blame_inline_internal(true, window, cx);
18885        cx.notify();
18886    }
18887
18888    pub fn open_git_blame_commit(
18889        &mut self,
18890        _: &OpenGitBlameCommit,
18891        window: &mut Window,
18892        cx: &mut Context<Self>,
18893    ) {
18894        self.open_git_blame_commit_internal(window, cx);
18895    }
18896
18897    fn open_git_blame_commit_internal(
18898        &mut self,
18899        window: &mut Window,
18900        cx: &mut Context<Self>,
18901    ) -> Option<()> {
18902        let blame = self.blame.as_ref()?;
18903        let snapshot = self.snapshot(window, cx);
18904        let cursor = self.selections.newest::<Point>(cx).head();
18905        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18906        let blame_entry = blame
18907            .update(cx, |blame, cx| {
18908                blame
18909                    .blame_for_rows(
18910                        &[RowInfo {
18911                            buffer_id: Some(buffer.remote_id()),
18912                            buffer_row: Some(point.row),
18913                            ..Default::default()
18914                        }],
18915                        cx,
18916                    )
18917                    .next()
18918            })
18919            .flatten()?;
18920        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18921        let repo = blame.read(cx).repository(cx)?;
18922        let workspace = self.workspace()?.downgrade();
18923        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18924        None
18925    }
18926
18927    pub fn git_blame_inline_enabled(&self) -> bool {
18928        self.git_blame_inline_enabled
18929    }
18930
18931    pub fn toggle_selection_menu(
18932        &mut self,
18933        _: &ToggleSelectionMenu,
18934        _: &mut Window,
18935        cx: &mut Context<Self>,
18936    ) {
18937        self.show_selection_menu = self
18938            .show_selection_menu
18939            .map(|show_selections_menu| !show_selections_menu)
18940            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18941
18942        cx.notify();
18943    }
18944
18945    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18946        self.show_selection_menu
18947            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18948    }
18949
18950    fn start_git_blame(
18951        &mut self,
18952        user_triggered: bool,
18953        window: &mut Window,
18954        cx: &mut Context<Self>,
18955    ) {
18956        if let Some(project) = self.project() {
18957            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18958                return;
18959            };
18960
18961            if buffer.read(cx).file().is_none() {
18962                return;
18963            }
18964
18965            let focused = self.focus_handle(cx).contains_focused(window, cx);
18966
18967            let project = project.clone();
18968            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18969            self.blame_subscription =
18970                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18971            self.blame = Some(blame);
18972        }
18973    }
18974
18975    fn toggle_git_blame_inline_internal(
18976        &mut self,
18977        user_triggered: bool,
18978        window: &mut Window,
18979        cx: &mut Context<Self>,
18980    ) {
18981        if self.git_blame_inline_enabled {
18982            self.git_blame_inline_enabled = false;
18983            self.show_git_blame_inline = false;
18984            self.show_git_blame_inline_delay_task.take();
18985        } else {
18986            self.git_blame_inline_enabled = true;
18987            self.start_git_blame_inline(user_triggered, window, cx);
18988        }
18989
18990        cx.notify();
18991    }
18992
18993    fn start_git_blame_inline(
18994        &mut self,
18995        user_triggered: bool,
18996        window: &mut Window,
18997        cx: &mut Context<Self>,
18998    ) {
18999        self.start_git_blame(user_triggered, window, cx);
19000
19001        if ProjectSettings::get_global(cx)
19002            .git
19003            .inline_blame_delay()
19004            .is_some()
19005        {
19006            self.start_inline_blame_timer(window, cx);
19007        } else {
19008            self.show_git_blame_inline = true
19009        }
19010    }
19011
19012    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19013        self.blame.as_ref()
19014    }
19015
19016    pub fn show_git_blame_gutter(&self) -> bool {
19017        self.show_git_blame_gutter
19018    }
19019
19020    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19021        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19022    }
19023
19024    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19025        self.show_git_blame_inline
19026            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19027            && !self.newest_selection_head_on_empty_line(cx)
19028            && self.has_blame_entries(cx)
19029    }
19030
19031    fn has_blame_entries(&self, cx: &App) -> bool {
19032        self.blame()
19033            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19034    }
19035
19036    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19037        let cursor_anchor = self.selections.newest_anchor().head();
19038
19039        let snapshot = self.buffer.read(cx).snapshot(cx);
19040        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19041
19042        snapshot.line_len(buffer_row) == 0
19043    }
19044
19045    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19046        let buffer_and_selection = maybe!({
19047            let selection = self.selections.newest::<Point>(cx);
19048            let selection_range = selection.range();
19049
19050            let multi_buffer = self.buffer().read(cx);
19051            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19052            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19053
19054            let (buffer, range, _) = if selection.reversed {
19055                buffer_ranges.first()
19056            } else {
19057                buffer_ranges.last()
19058            }?;
19059
19060            let selection = text::ToPoint::to_point(&range.start, buffer).row
19061                ..text::ToPoint::to_point(&range.end, buffer).row;
19062            Some((
19063                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
19064                selection,
19065            ))
19066        });
19067
19068        let Some((buffer, selection)) = buffer_and_selection else {
19069            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19070        };
19071
19072        let Some(project) = self.project() else {
19073            return Task::ready(Err(anyhow!("editor does not have project")));
19074        };
19075
19076        project.update(cx, |project, cx| {
19077            project.get_permalink_to_line(&buffer, selection, cx)
19078        })
19079    }
19080
19081    pub fn copy_permalink_to_line(
19082        &mut self,
19083        _: &CopyPermalinkToLine,
19084        window: &mut Window,
19085        cx: &mut Context<Self>,
19086    ) {
19087        let permalink_task = self.get_permalink_to_line(cx);
19088        let workspace = self.workspace();
19089
19090        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19091            Ok(permalink) => {
19092                cx.update(|_, cx| {
19093                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19094                })
19095                .ok();
19096            }
19097            Err(err) => {
19098                let message = format!("Failed to copy permalink: {err}");
19099
19100                anyhow::Result::<()>::Err(err).log_err();
19101
19102                if let Some(workspace) = workspace {
19103                    workspace
19104                        .update_in(cx, |workspace, _, cx| {
19105                            struct CopyPermalinkToLine;
19106
19107                            workspace.show_toast(
19108                                Toast::new(
19109                                    NotificationId::unique::<CopyPermalinkToLine>(),
19110                                    message,
19111                                ),
19112                                cx,
19113                            )
19114                        })
19115                        .ok();
19116                }
19117            }
19118        })
19119        .detach();
19120    }
19121
19122    pub fn copy_file_location(
19123        &mut self,
19124        _: &CopyFileLocation,
19125        _: &mut Window,
19126        cx: &mut Context<Self>,
19127    ) {
19128        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19129        if let Some(file) = self.target_file(cx)
19130            && let Some(path) = file.path().to_str()
19131        {
19132            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19133        }
19134    }
19135
19136    pub fn open_permalink_to_line(
19137        &mut self,
19138        _: &OpenPermalinkToLine,
19139        window: &mut Window,
19140        cx: &mut Context<Self>,
19141    ) {
19142        let permalink_task = self.get_permalink_to_line(cx);
19143        let workspace = self.workspace();
19144
19145        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19146            Ok(permalink) => {
19147                cx.update(|_, cx| {
19148                    cx.open_url(permalink.as_ref());
19149                })
19150                .ok();
19151            }
19152            Err(err) => {
19153                let message = format!("Failed to open permalink: {err}");
19154
19155                anyhow::Result::<()>::Err(err).log_err();
19156
19157                if let Some(workspace) = workspace {
19158                    workspace
19159                        .update(cx, |workspace, cx| {
19160                            struct OpenPermalinkToLine;
19161
19162                            workspace.show_toast(
19163                                Toast::new(
19164                                    NotificationId::unique::<OpenPermalinkToLine>(),
19165                                    message,
19166                                ),
19167                                cx,
19168                            )
19169                        })
19170                        .ok();
19171                }
19172            }
19173        })
19174        .detach();
19175    }
19176
19177    pub fn insert_uuid_v4(
19178        &mut self,
19179        _: &InsertUuidV4,
19180        window: &mut Window,
19181        cx: &mut Context<Self>,
19182    ) {
19183        self.insert_uuid(UuidVersion::V4, window, cx);
19184    }
19185
19186    pub fn insert_uuid_v7(
19187        &mut self,
19188        _: &InsertUuidV7,
19189        window: &mut Window,
19190        cx: &mut Context<Self>,
19191    ) {
19192        self.insert_uuid(UuidVersion::V7, window, cx);
19193    }
19194
19195    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19196        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19197        self.transact(window, cx, |this, window, cx| {
19198            let edits = this
19199                .selections
19200                .all::<Point>(cx)
19201                .into_iter()
19202                .map(|selection| {
19203                    let uuid = match version {
19204                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19205                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19206                    };
19207
19208                    (selection.range(), uuid.to_string())
19209                });
19210            this.edit(edits, cx);
19211            this.refresh_edit_prediction(true, false, window, cx);
19212        });
19213    }
19214
19215    pub fn open_selections_in_multibuffer(
19216        &mut self,
19217        _: &OpenSelectionsInMultibuffer,
19218        window: &mut Window,
19219        cx: &mut Context<Self>,
19220    ) {
19221        let multibuffer = self.buffer.read(cx);
19222
19223        let Some(buffer) = multibuffer.as_singleton() else {
19224            return;
19225        };
19226
19227        let Some(workspace) = self.workspace() else {
19228            return;
19229        };
19230
19231        let title = multibuffer.title(cx).to_string();
19232
19233        let locations = self
19234            .selections
19235            .all_anchors(cx)
19236            .into_iter()
19237            .map(|selection| Location {
19238                buffer: buffer.clone(),
19239                range: selection.start.text_anchor..selection.end.text_anchor,
19240            })
19241            .collect::<Vec<_>>();
19242
19243        cx.spawn_in(window, async move |_, cx| {
19244            workspace.update_in(cx, |workspace, window, cx| {
19245                Self::open_locations_in_multibuffer(
19246                    workspace,
19247                    locations,
19248                    format!("Selections for '{title}'"),
19249                    false,
19250                    MultibufferSelectionMode::All,
19251                    window,
19252                    cx,
19253                );
19254            })
19255        })
19256        .detach();
19257    }
19258
19259    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19260    /// last highlight added will be used.
19261    ///
19262    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19263    pub fn highlight_rows<T: 'static>(
19264        &mut self,
19265        range: Range<Anchor>,
19266        color: Hsla,
19267        options: RowHighlightOptions,
19268        cx: &mut Context<Self>,
19269    ) {
19270        let snapshot = self.buffer().read(cx).snapshot(cx);
19271        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19272        let ix = row_highlights.binary_search_by(|highlight| {
19273            Ordering::Equal
19274                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19275                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19276        });
19277
19278        if let Err(mut ix) = ix {
19279            let index = post_inc(&mut self.highlight_order);
19280
19281            // If this range intersects with the preceding highlight, then merge it with
19282            // the preceding highlight. Otherwise insert a new highlight.
19283            let mut merged = false;
19284            if ix > 0 {
19285                let prev_highlight = &mut row_highlights[ix - 1];
19286                if prev_highlight
19287                    .range
19288                    .end
19289                    .cmp(&range.start, &snapshot)
19290                    .is_ge()
19291                {
19292                    ix -= 1;
19293                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19294                        prev_highlight.range.end = range.end;
19295                    }
19296                    merged = true;
19297                    prev_highlight.index = index;
19298                    prev_highlight.color = color;
19299                    prev_highlight.options = options;
19300                }
19301            }
19302
19303            if !merged {
19304                row_highlights.insert(
19305                    ix,
19306                    RowHighlight {
19307                        range: range.clone(),
19308                        index,
19309                        color,
19310                        options,
19311                        type_id: TypeId::of::<T>(),
19312                    },
19313                );
19314            }
19315
19316            // If any of the following highlights intersect with this one, merge them.
19317            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19318                let highlight = &row_highlights[ix];
19319                if next_highlight
19320                    .range
19321                    .start
19322                    .cmp(&highlight.range.end, &snapshot)
19323                    .is_le()
19324                {
19325                    if next_highlight
19326                        .range
19327                        .end
19328                        .cmp(&highlight.range.end, &snapshot)
19329                        .is_gt()
19330                    {
19331                        row_highlights[ix].range.end = next_highlight.range.end;
19332                    }
19333                    row_highlights.remove(ix + 1);
19334                } else {
19335                    break;
19336                }
19337            }
19338        }
19339    }
19340
19341    /// Remove any highlighted row ranges of the given type that intersect the
19342    /// given ranges.
19343    pub fn remove_highlighted_rows<T: 'static>(
19344        &mut self,
19345        ranges_to_remove: Vec<Range<Anchor>>,
19346        cx: &mut Context<Self>,
19347    ) {
19348        let snapshot = self.buffer().read(cx).snapshot(cx);
19349        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19350        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19351        row_highlights.retain(|highlight| {
19352            while let Some(range_to_remove) = ranges_to_remove.peek() {
19353                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19354                    Ordering::Less | Ordering::Equal => {
19355                        ranges_to_remove.next();
19356                    }
19357                    Ordering::Greater => {
19358                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19359                            Ordering::Less | Ordering::Equal => {
19360                                return false;
19361                            }
19362                            Ordering::Greater => break,
19363                        }
19364                    }
19365                }
19366            }
19367
19368            true
19369        })
19370    }
19371
19372    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19373    pub fn clear_row_highlights<T: 'static>(&mut self) {
19374        self.highlighted_rows.remove(&TypeId::of::<T>());
19375    }
19376
19377    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19378    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19379        self.highlighted_rows
19380            .get(&TypeId::of::<T>())
19381            .map_or(&[] as &[_], |vec| vec.as_slice())
19382            .iter()
19383            .map(|highlight| (highlight.range.clone(), highlight.color))
19384    }
19385
19386    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19387    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19388    /// Allows to ignore certain kinds of highlights.
19389    pub fn highlighted_display_rows(
19390        &self,
19391        window: &mut Window,
19392        cx: &mut App,
19393    ) -> BTreeMap<DisplayRow, LineHighlight> {
19394        let snapshot = self.snapshot(window, cx);
19395        let mut used_highlight_orders = HashMap::default();
19396        self.highlighted_rows
19397            .iter()
19398            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19399            .fold(
19400                BTreeMap::<DisplayRow, LineHighlight>::new(),
19401                |mut unique_rows, highlight| {
19402                    let start = highlight.range.start.to_display_point(&snapshot);
19403                    let end = highlight.range.end.to_display_point(&snapshot);
19404                    let start_row = start.row().0;
19405                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19406                        && end.column() == 0
19407                    {
19408                        end.row().0.saturating_sub(1)
19409                    } else {
19410                        end.row().0
19411                    };
19412                    for row in start_row..=end_row {
19413                        let used_index =
19414                            used_highlight_orders.entry(row).or_insert(highlight.index);
19415                        if highlight.index >= *used_index {
19416                            *used_index = highlight.index;
19417                            unique_rows.insert(
19418                                DisplayRow(row),
19419                                LineHighlight {
19420                                    include_gutter: highlight.options.include_gutter,
19421                                    border: None,
19422                                    background: highlight.color.into(),
19423                                    type_id: Some(highlight.type_id),
19424                                },
19425                            );
19426                        }
19427                    }
19428                    unique_rows
19429                },
19430            )
19431    }
19432
19433    pub fn highlighted_display_row_for_autoscroll(
19434        &self,
19435        snapshot: &DisplaySnapshot,
19436    ) -> Option<DisplayRow> {
19437        self.highlighted_rows
19438            .values()
19439            .flat_map(|highlighted_rows| highlighted_rows.iter())
19440            .filter_map(|highlight| {
19441                if highlight.options.autoscroll {
19442                    Some(highlight.range.start.to_display_point(snapshot).row())
19443                } else {
19444                    None
19445                }
19446            })
19447            .min()
19448    }
19449
19450    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19451        self.highlight_background::<SearchWithinRange>(
19452            ranges,
19453            |colors| colors.colors().editor_document_highlight_read_background,
19454            cx,
19455        )
19456    }
19457
19458    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19459        self.breadcrumb_header = Some(new_header);
19460    }
19461
19462    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19463        self.clear_background_highlights::<SearchWithinRange>(cx);
19464    }
19465
19466    pub fn highlight_background<T: 'static>(
19467        &mut self,
19468        ranges: &[Range<Anchor>],
19469        color_fetcher: fn(&Theme) -> Hsla,
19470        cx: &mut Context<Self>,
19471    ) {
19472        self.background_highlights.insert(
19473            HighlightKey::Type(TypeId::of::<T>()),
19474            (color_fetcher, Arc::from(ranges)),
19475        );
19476        self.scrollbar_marker_state.dirty = true;
19477        cx.notify();
19478    }
19479
19480    pub fn highlight_background_key<T: 'static>(
19481        &mut self,
19482        key: usize,
19483        ranges: &[Range<Anchor>],
19484        color_fetcher: fn(&Theme) -> Hsla,
19485        cx: &mut Context<Self>,
19486    ) {
19487        self.background_highlights.insert(
19488            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19489            (color_fetcher, Arc::from(ranges)),
19490        );
19491        self.scrollbar_marker_state.dirty = true;
19492        cx.notify();
19493    }
19494
19495    pub fn clear_background_highlights<T: 'static>(
19496        &mut self,
19497        cx: &mut Context<Self>,
19498    ) -> Option<BackgroundHighlight> {
19499        let text_highlights = self
19500            .background_highlights
19501            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19502        if !text_highlights.1.is_empty() {
19503            self.scrollbar_marker_state.dirty = true;
19504            cx.notify();
19505        }
19506        Some(text_highlights)
19507    }
19508
19509    pub fn highlight_gutter<T: 'static>(
19510        &mut self,
19511        ranges: impl Into<Vec<Range<Anchor>>>,
19512        color_fetcher: fn(&App) -> Hsla,
19513        cx: &mut Context<Self>,
19514    ) {
19515        self.gutter_highlights
19516            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19517        cx.notify();
19518    }
19519
19520    pub fn clear_gutter_highlights<T: 'static>(
19521        &mut self,
19522        cx: &mut Context<Self>,
19523    ) -> Option<GutterHighlight> {
19524        cx.notify();
19525        self.gutter_highlights.remove(&TypeId::of::<T>())
19526    }
19527
19528    pub fn insert_gutter_highlight<T: 'static>(
19529        &mut self,
19530        range: Range<Anchor>,
19531        color_fetcher: fn(&App) -> Hsla,
19532        cx: &mut Context<Self>,
19533    ) {
19534        let snapshot = self.buffer().read(cx).snapshot(cx);
19535        let mut highlights = self
19536            .gutter_highlights
19537            .remove(&TypeId::of::<T>())
19538            .map(|(_, highlights)| highlights)
19539            .unwrap_or_default();
19540        let ix = highlights.binary_search_by(|highlight| {
19541            Ordering::Equal
19542                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19543                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19544        });
19545        if let Err(ix) = ix {
19546            highlights.insert(ix, range);
19547        }
19548        self.gutter_highlights
19549            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19550    }
19551
19552    pub fn remove_gutter_highlights<T: 'static>(
19553        &mut self,
19554        ranges_to_remove: Vec<Range<Anchor>>,
19555        cx: &mut Context<Self>,
19556    ) {
19557        let snapshot = self.buffer().read(cx).snapshot(cx);
19558        let Some((color_fetcher, mut gutter_highlights)) =
19559            self.gutter_highlights.remove(&TypeId::of::<T>())
19560        else {
19561            return;
19562        };
19563        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19564        gutter_highlights.retain(|highlight| {
19565            while let Some(range_to_remove) = ranges_to_remove.peek() {
19566                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19567                    Ordering::Less | Ordering::Equal => {
19568                        ranges_to_remove.next();
19569                    }
19570                    Ordering::Greater => {
19571                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19572                            Ordering::Less | Ordering::Equal => {
19573                                return false;
19574                            }
19575                            Ordering::Greater => break,
19576                        }
19577                    }
19578                }
19579            }
19580
19581            true
19582        });
19583        self.gutter_highlights
19584            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19585    }
19586
19587    #[cfg(feature = "test-support")]
19588    pub fn all_text_highlights(
19589        &self,
19590        window: &mut Window,
19591        cx: &mut Context<Self>,
19592    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19593        let snapshot = self.snapshot(window, cx);
19594        self.display_map.update(cx, |display_map, _| {
19595            display_map
19596                .all_text_highlights()
19597                .map(|highlight| {
19598                    let (style, ranges) = highlight.as_ref();
19599                    (
19600                        *style,
19601                        ranges
19602                            .iter()
19603                            .map(|range| range.clone().to_display_points(&snapshot))
19604                            .collect(),
19605                    )
19606                })
19607                .collect()
19608        })
19609    }
19610
19611    #[cfg(feature = "test-support")]
19612    pub fn all_text_background_highlights(
19613        &self,
19614        window: &mut Window,
19615        cx: &mut Context<Self>,
19616    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19617        let snapshot = self.snapshot(window, cx);
19618        let buffer = &snapshot.buffer_snapshot;
19619        let start = buffer.anchor_before(0);
19620        let end = buffer.anchor_after(buffer.len());
19621        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19622    }
19623
19624    #[cfg(feature = "test-support")]
19625    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19626        let snapshot = self.buffer().read(cx).snapshot(cx);
19627
19628        let highlights = self
19629            .background_highlights
19630            .get(&HighlightKey::Type(TypeId::of::<
19631                items::BufferSearchHighlights,
19632            >()));
19633
19634        if let Some((_color, ranges)) = highlights {
19635            ranges
19636                .iter()
19637                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19638                .collect_vec()
19639        } else {
19640            vec![]
19641        }
19642    }
19643
19644    fn document_highlights_for_position<'a>(
19645        &'a self,
19646        position: Anchor,
19647        buffer: &'a MultiBufferSnapshot,
19648    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19649        let read_highlights = self
19650            .background_highlights
19651            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19652            .map(|h| &h.1);
19653        let write_highlights = self
19654            .background_highlights
19655            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19656            .map(|h| &h.1);
19657        let left_position = position.bias_left(buffer);
19658        let right_position = position.bias_right(buffer);
19659        read_highlights
19660            .into_iter()
19661            .chain(write_highlights)
19662            .flat_map(move |ranges| {
19663                let start_ix = match ranges.binary_search_by(|probe| {
19664                    let cmp = probe.end.cmp(&left_position, buffer);
19665                    if cmp.is_ge() {
19666                        Ordering::Greater
19667                    } else {
19668                        Ordering::Less
19669                    }
19670                }) {
19671                    Ok(i) | Err(i) => i,
19672                };
19673
19674                ranges[start_ix..]
19675                    .iter()
19676                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19677            })
19678    }
19679
19680    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19681        self.background_highlights
19682            .get(&HighlightKey::Type(TypeId::of::<T>()))
19683            .is_some_and(|(_, highlights)| !highlights.is_empty())
19684    }
19685
19686    pub fn background_highlights_in_range(
19687        &self,
19688        search_range: Range<Anchor>,
19689        display_snapshot: &DisplaySnapshot,
19690        theme: &Theme,
19691    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19692        let mut results = Vec::new();
19693        for (color_fetcher, ranges) in self.background_highlights.values() {
19694            let color = color_fetcher(theme);
19695            let start_ix = match ranges.binary_search_by(|probe| {
19696                let cmp = probe
19697                    .end
19698                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19699                if cmp.is_gt() {
19700                    Ordering::Greater
19701                } else {
19702                    Ordering::Less
19703                }
19704            }) {
19705                Ok(i) | Err(i) => i,
19706            };
19707            for range in &ranges[start_ix..] {
19708                if range
19709                    .start
19710                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19711                    .is_ge()
19712                {
19713                    break;
19714                }
19715
19716                let start = range.start.to_display_point(display_snapshot);
19717                let end = range.end.to_display_point(display_snapshot);
19718                results.push((start..end, color))
19719            }
19720        }
19721        results
19722    }
19723
19724    pub fn background_highlight_row_ranges<T: 'static>(
19725        &self,
19726        search_range: Range<Anchor>,
19727        display_snapshot: &DisplaySnapshot,
19728        count: usize,
19729    ) -> Vec<RangeInclusive<DisplayPoint>> {
19730        let mut results = Vec::new();
19731        let Some((_, ranges)) = self
19732            .background_highlights
19733            .get(&HighlightKey::Type(TypeId::of::<T>()))
19734        else {
19735            return vec![];
19736        };
19737
19738        let start_ix = match ranges.binary_search_by(|probe| {
19739            let cmp = probe
19740                .end
19741                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19742            if cmp.is_gt() {
19743                Ordering::Greater
19744            } else {
19745                Ordering::Less
19746            }
19747        }) {
19748            Ok(i) | Err(i) => i,
19749        };
19750        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19751            if let (Some(start_display), Some(end_display)) = (start, end) {
19752                results.push(
19753                    start_display.to_display_point(display_snapshot)
19754                        ..=end_display.to_display_point(display_snapshot),
19755                );
19756            }
19757        };
19758        let mut start_row: Option<Point> = None;
19759        let mut end_row: Option<Point> = None;
19760        if ranges.len() > count {
19761            return Vec::new();
19762        }
19763        for range in &ranges[start_ix..] {
19764            if range
19765                .start
19766                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19767                .is_ge()
19768            {
19769                break;
19770            }
19771            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19772            if let Some(current_row) = &end_row
19773                && end.row == current_row.row
19774            {
19775                continue;
19776            }
19777            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19778            if start_row.is_none() {
19779                assert_eq!(end_row, None);
19780                start_row = Some(start);
19781                end_row = Some(end);
19782                continue;
19783            }
19784            if let Some(current_end) = end_row.as_mut() {
19785                if start.row > current_end.row + 1 {
19786                    push_region(start_row, end_row);
19787                    start_row = Some(start);
19788                    end_row = Some(end);
19789                } else {
19790                    // Merge two hunks.
19791                    *current_end = end;
19792                }
19793            } else {
19794                unreachable!();
19795            }
19796        }
19797        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19798        push_region(start_row, end_row);
19799        results
19800    }
19801
19802    pub fn gutter_highlights_in_range(
19803        &self,
19804        search_range: Range<Anchor>,
19805        display_snapshot: &DisplaySnapshot,
19806        cx: &App,
19807    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19808        let mut results = Vec::new();
19809        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19810            let color = color_fetcher(cx);
19811            let start_ix = match ranges.binary_search_by(|probe| {
19812                let cmp = probe
19813                    .end
19814                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19815                if cmp.is_gt() {
19816                    Ordering::Greater
19817                } else {
19818                    Ordering::Less
19819                }
19820            }) {
19821                Ok(i) | Err(i) => i,
19822            };
19823            for range in &ranges[start_ix..] {
19824                if range
19825                    .start
19826                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19827                    .is_ge()
19828                {
19829                    break;
19830                }
19831
19832                let start = range.start.to_display_point(display_snapshot);
19833                let end = range.end.to_display_point(display_snapshot);
19834                results.push((start..end, color))
19835            }
19836        }
19837        results
19838    }
19839
19840    /// Get the text ranges corresponding to the redaction query
19841    pub fn redacted_ranges(
19842        &self,
19843        search_range: Range<Anchor>,
19844        display_snapshot: &DisplaySnapshot,
19845        cx: &App,
19846    ) -> Vec<Range<DisplayPoint>> {
19847        display_snapshot
19848            .buffer_snapshot
19849            .redacted_ranges(search_range, |file| {
19850                if let Some(file) = file {
19851                    file.is_private()
19852                        && EditorSettings::get(
19853                            Some(SettingsLocation {
19854                                worktree_id: file.worktree_id(cx),
19855                                path: file.path().as_ref(),
19856                            }),
19857                            cx,
19858                        )
19859                        .redact_private_values
19860                } else {
19861                    false
19862                }
19863            })
19864            .map(|range| {
19865                range.start.to_display_point(display_snapshot)
19866                    ..range.end.to_display_point(display_snapshot)
19867            })
19868            .collect()
19869    }
19870
19871    pub fn highlight_text_key<T: 'static>(
19872        &mut self,
19873        key: usize,
19874        ranges: Vec<Range<Anchor>>,
19875        style: HighlightStyle,
19876        cx: &mut Context<Self>,
19877    ) {
19878        self.display_map.update(cx, |map, _| {
19879            map.highlight_text(
19880                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19881                ranges,
19882                style,
19883            );
19884        });
19885        cx.notify();
19886    }
19887
19888    pub fn highlight_text<T: 'static>(
19889        &mut self,
19890        ranges: Vec<Range<Anchor>>,
19891        style: HighlightStyle,
19892        cx: &mut Context<Self>,
19893    ) {
19894        self.display_map.update(cx, |map, _| {
19895            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19896        });
19897        cx.notify();
19898    }
19899
19900    pub(crate) fn highlight_inlays<T: 'static>(
19901        &mut self,
19902        highlights: Vec<InlayHighlight>,
19903        style: HighlightStyle,
19904        cx: &mut Context<Self>,
19905    ) {
19906        self.display_map.update(cx, |map, _| {
19907            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19908        });
19909        cx.notify();
19910    }
19911
19912    pub fn text_highlights<'a, T: 'static>(
19913        &'a self,
19914        cx: &'a App,
19915    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19916        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19917    }
19918
19919    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19920        let cleared = self
19921            .display_map
19922            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19923        if cleared {
19924            cx.notify();
19925        }
19926    }
19927
19928    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19929        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19930            && self.focus_handle.is_focused(window)
19931    }
19932
19933    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19934        self.show_cursor_when_unfocused = is_enabled;
19935        cx.notify();
19936    }
19937
19938    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19939        cx.notify();
19940    }
19941
19942    fn on_debug_session_event(
19943        &mut self,
19944        _session: Entity<Session>,
19945        event: &SessionEvent,
19946        cx: &mut Context<Self>,
19947    ) {
19948        match event {
19949            SessionEvent::InvalidateInlineValue => {
19950                self.refresh_inline_values(cx);
19951            }
19952            _ => {}
19953        }
19954    }
19955
19956    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19957        let Some(project) = self.project.clone() else {
19958            return;
19959        };
19960
19961        if !self.inline_value_cache.enabled {
19962            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19963            self.splice_inlays(&inlays, Vec::new(), cx);
19964            return;
19965        }
19966
19967        let current_execution_position = self
19968            .highlighted_rows
19969            .get(&TypeId::of::<ActiveDebugLine>())
19970            .and_then(|lines| lines.last().map(|line| line.range.end));
19971
19972        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19973            let inline_values = editor
19974                .update(cx, |editor, cx| {
19975                    let Some(current_execution_position) = current_execution_position else {
19976                        return Some(Task::ready(Ok(Vec::new())));
19977                    };
19978
19979                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19980                        let snapshot = buffer.snapshot(cx);
19981
19982                        let excerpt = snapshot.excerpt_containing(
19983                            current_execution_position..current_execution_position,
19984                        )?;
19985
19986                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19987                    })?;
19988
19989                    let range =
19990                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19991
19992                    project.inline_values(buffer, range, cx)
19993                })
19994                .ok()
19995                .flatten()?
19996                .await
19997                .context("refreshing debugger inlays")
19998                .log_err()?;
19999
20000            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20001
20002            for (buffer_id, inline_value) in inline_values
20003                .into_iter()
20004                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20005            {
20006                buffer_inline_values
20007                    .entry(buffer_id)
20008                    .or_default()
20009                    .push(inline_value);
20010            }
20011
20012            editor
20013                .update(cx, |editor, cx| {
20014                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20015                    let mut new_inlays = Vec::default();
20016
20017                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20018                        let buffer_id = buffer_snapshot.remote_id();
20019                        buffer_inline_values
20020                            .get(&buffer_id)
20021                            .into_iter()
20022                            .flatten()
20023                            .for_each(|hint| {
20024                                let inlay = Inlay::debugger(
20025                                    post_inc(&mut editor.next_inlay_id),
20026                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20027                                    hint.text(),
20028                                );
20029                                if !inlay.text.chars().contains(&'\n') {
20030                                    new_inlays.push(inlay);
20031                                }
20032                            });
20033                    }
20034
20035                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20036                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20037
20038                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20039                })
20040                .ok()?;
20041            Some(())
20042        });
20043    }
20044
20045    fn on_buffer_event(
20046        &mut self,
20047        multibuffer: &Entity<MultiBuffer>,
20048        event: &multi_buffer::Event,
20049        window: &mut Window,
20050        cx: &mut Context<Self>,
20051    ) {
20052        match event {
20053            multi_buffer::Event::Edited {
20054                singleton_buffer_edited,
20055                edited_buffer,
20056            } => {
20057                self.scrollbar_marker_state.dirty = true;
20058                self.active_indent_guides_state.dirty = true;
20059                self.refresh_active_diagnostics(cx);
20060                self.refresh_code_actions(window, cx);
20061                self.refresh_selected_text_highlights(true, window, cx);
20062                self.refresh_single_line_folds(window, cx);
20063                refresh_matching_bracket_highlights(self, window, cx);
20064                if self.has_active_edit_prediction() {
20065                    self.update_visible_edit_prediction(window, cx);
20066                }
20067                if let Some(project) = self.project.as_ref()
20068                    && let Some(edited_buffer) = edited_buffer
20069                {
20070                    project.update(cx, |project, cx| {
20071                        self.registered_buffers
20072                            .entry(edited_buffer.read(cx).remote_id())
20073                            .or_insert_with(|| {
20074                                project.register_buffer_with_language_servers(edited_buffer, cx)
20075                            });
20076                    });
20077                }
20078                cx.emit(EditorEvent::BufferEdited);
20079                cx.emit(SearchEvent::MatchesInvalidated);
20080
20081                if let Some(buffer) = edited_buffer {
20082                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20083                }
20084
20085                if *singleton_buffer_edited {
20086                    if let Some(buffer) = edited_buffer
20087                        && buffer.read(cx).file().is_none()
20088                    {
20089                        cx.emit(EditorEvent::TitleChanged);
20090                    }
20091                    if let Some(project) = &self.project {
20092                        #[allow(clippy::mutable_key_type)]
20093                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20094                            multibuffer
20095                                .all_buffers()
20096                                .into_iter()
20097                                .filter_map(|buffer| {
20098                                    buffer.update(cx, |buffer, cx| {
20099                                        let language = buffer.language()?;
20100                                        let should_discard = project.update(cx, |project, cx| {
20101                                            project.is_local()
20102                                                && !project.has_language_servers_for(buffer, cx)
20103                                        });
20104                                        should_discard.not().then_some(language.clone())
20105                                    })
20106                                })
20107                                .collect::<HashSet<_>>()
20108                        });
20109                        if !languages_affected.is_empty() {
20110                            self.refresh_inlay_hints(
20111                                InlayHintRefreshReason::BufferEdited(languages_affected),
20112                                cx,
20113                            );
20114                        }
20115                    }
20116                }
20117
20118                let Some(project) = &self.project else { return };
20119                let (telemetry, is_via_ssh) = {
20120                    let project = project.read(cx);
20121                    let telemetry = project.client().telemetry().clone();
20122                    let is_via_ssh = project.is_via_ssh();
20123                    (telemetry, is_via_ssh)
20124                };
20125                refresh_linked_ranges(self, window, cx);
20126                telemetry.log_edit_event("editor", is_via_ssh);
20127            }
20128            multi_buffer::Event::ExcerptsAdded {
20129                buffer,
20130                predecessor,
20131                excerpts,
20132            } => {
20133                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20134                let buffer_id = buffer.read(cx).remote_id();
20135                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20136                    && let Some(project) = &self.project
20137                {
20138                    update_uncommitted_diff_for_buffer(
20139                        cx.entity(),
20140                        project,
20141                        [buffer.clone()],
20142                        self.buffer.clone(),
20143                        cx,
20144                    )
20145                    .detach();
20146                }
20147                self.update_lsp_data(false, Some(buffer_id), window, cx);
20148                cx.emit(EditorEvent::ExcerptsAdded {
20149                    buffer: buffer.clone(),
20150                    predecessor: *predecessor,
20151                    excerpts: excerpts.clone(),
20152                });
20153                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20154            }
20155            multi_buffer::Event::ExcerptsRemoved {
20156                ids,
20157                removed_buffer_ids,
20158            } => {
20159                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20160                let buffer = self.buffer.read(cx);
20161                self.registered_buffers
20162                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20163                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20164                cx.emit(EditorEvent::ExcerptsRemoved {
20165                    ids: ids.clone(),
20166                    removed_buffer_ids: removed_buffer_ids.clone(),
20167                });
20168            }
20169            multi_buffer::Event::ExcerptsEdited {
20170                excerpt_ids,
20171                buffer_ids,
20172            } => {
20173                self.display_map.update(cx, |map, cx| {
20174                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20175                });
20176                cx.emit(EditorEvent::ExcerptsEdited {
20177                    ids: excerpt_ids.clone(),
20178                });
20179            }
20180            multi_buffer::Event::ExcerptsExpanded { ids } => {
20181                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20182                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20183            }
20184            multi_buffer::Event::Reparsed(buffer_id) => {
20185                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20186                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20187
20188                cx.emit(EditorEvent::Reparsed(*buffer_id));
20189            }
20190            multi_buffer::Event::DiffHunksToggled => {
20191                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20192            }
20193            multi_buffer::Event::LanguageChanged(buffer_id) => {
20194                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20195                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20196                cx.emit(EditorEvent::Reparsed(*buffer_id));
20197                cx.notify();
20198            }
20199            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20200            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20201            multi_buffer::Event::FileHandleChanged
20202            | multi_buffer::Event::Reloaded
20203            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20204            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20205            multi_buffer::Event::DiagnosticsUpdated => {
20206                self.update_diagnostics_state(window, cx);
20207            }
20208            _ => {}
20209        };
20210    }
20211
20212    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20213        if !self.diagnostics_enabled() {
20214            return;
20215        }
20216        self.refresh_active_diagnostics(cx);
20217        self.refresh_inline_diagnostics(true, window, cx);
20218        self.scrollbar_marker_state.dirty = true;
20219        cx.notify();
20220    }
20221
20222    pub fn start_temporary_diff_override(&mut self) {
20223        self.load_diff_task.take();
20224        self.temporary_diff_override = true;
20225    }
20226
20227    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20228        self.temporary_diff_override = false;
20229        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20230        self.buffer.update(cx, |buffer, cx| {
20231            buffer.set_all_diff_hunks_collapsed(cx);
20232        });
20233
20234        if let Some(project) = self.project.clone() {
20235            self.load_diff_task = Some(
20236                update_uncommitted_diff_for_buffer(
20237                    cx.entity(),
20238                    &project,
20239                    self.buffer.read(cx).all_buffers(),
20240                    self.buffer.clone(),
20241                    cx,
20242                )
20243                .shared(),
20244            );
20245        }
20246    }
20247
20248    fn on_display_map_changed(
20249        &mut self,
20250        _: Entity<DisplayMap>,
20251        _: &mut Window,
20252        cx: &mut Context<Self>,
20253    ) {
20254        cx.notify();
20255    }
20256
20257    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20258        if self.diagnostics_enabled() {
20259            let new_severity = EditorSettings::get_global(cx)
20260                .diagnostics_max_severity
20261                .unwrap_or(DiagnosticSeverity::Hint);
20262            self.set_max_diagnostics_severity(new_severity, cx);
20263        }
20264        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20265        self.update_edit_prediction_settings(cx);
20266        self.refresh_edit_prediction(true, false, window, cx);
20267        self.refresh_inline_values(cx);
20268        self.refresh_inlay_hints(
20269            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20270                self.selections.newest_anchor().head(),
20271                &self.buffer.read(cx).snapshot(cx),
20272                cx,
20273            )),
20274            cx,
20275        );
20276
20277        let old_cursor_shape = self.cursor_shape;
20278        let old_show_breadcrumbs = self.show_breadcrumbs;
20279
20280        {
20281            let editor_settings = EditorSettings::get_global(cx);
20282            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20283            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20284            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20285            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20286        }
20287
20288        if old_cursor_shape != self.cursor_shape {
20289            cx.emit(EditorEvent::CursorShapeChanged);
20290        }
20291
20292        if old_show_breadcrumbs != self.show_breadcrumbs {
20293            cx.emit(EditorEvent::BreadcrumbsChanged);
20294        }
20295
20296        let project_settings = ProjectSettings::get_global(cx);
20297        self.serialize_dirty_buffers =
20298            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20299
20300        if self.mode.is_full() {
20301            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20302            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20303            if self.show_inline_diagnostics != show_inline_diagnostics {
20304                self.show_inline_diagnostics = show_inline_diagnostics;
20305                self.refresh_inline_diagnostics(false, window, cx);
20306            }
20307
20308            if self.git_blame_inline_enabled != inline_blame_enabled {
20309                self.toggle_git_blame_inline_internal(false, window, cx);
20310            }
20311
20312            let minimap_settings = EditorSettings::get_global(cx).minimap;
20313            if self.minimap_visibility != MinimapVisibility::Disabled {
20314                if self.minimap_visibility.settings_visibility()
20315                    != minimap_settings.minimap_enabled()
20316                {
20317                    self.set_minimap_visibility(
20318                        MinimapVisibility::for_mode(self.mode(), cx),
20319                        window,
20320                        cx,
20321                    );
20322                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20323                    minimap_entity.update(cx, |minimap_editor, cx| {
20324                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20325                    })
20326                }
20327            }
20328        }
20329
20330        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20331            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20332        }) {
20333            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20334                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20335            }
20336            self.refresh_colors(false, None, window, cx);
20337        }
20338
20339        cx.notify();
20340    }
20341
20342    pub fn set_searchable(&mut self, searchable: bool) {
20343        self.searchable = searchable;
20344    }
20345
20346    pub fn searchable(&self) -> bool {
20347        self.searchable
20348    }
20349
20350    fn open_proposed_changes_editor(
20351        &mut self,
20352        _: &OpenProposedChangesEditor,
20353        window: &mut Window,
20354        cx: &mut Context<Self>,
20355    ) {
20356        let Some(workspace) = self.workspace() else {
20357            cx.propagate();
20358            return;
20359        };
20360
20361        let selections = self.selections.all::<usize>(cx);
20362        let multi_buffer = self.buffer.read(cx);
20363        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20364        let mut new_selections_by_buffer = HashMap::default();
20365        for selection in selections {
20366            for (buffer, range, _) in
20367                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20368            {
20369                let mut range = range.to_point(buffer);
20370                range.start.column = 0;
20371                range.end.column = buffer.line_len(range.end.row);
20372                new_selections_by_buffer
20373                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20374                    .or_insert(Vec::new())
20375                    .push(range)
20376            }
20377        }
20378
20379        let proposed_changes_buffers = new_selections_by_buffer
20380            .into_iter()
20381            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20382            .collect::<Vec<_>>();
20383        let proposed_changes_editor = cx.new(|cx| {
20384            ProposedChangesEditor::new(
20385                "Proposed changes",
20386                proposed_changes_buffers,
20387                self.project.clone(),
20388                window,
20389                cx,
20390            )
20391        });
20392
20393        window.defer(cx, move |window, cx| {
20394            workspace.update(cx, |workspace, cx| {
20395                workspace.active_pane().update(cx, |pane, cx| {
20396                    pane.add_item(
20397                        Box::new(proposed_changes_editor),
20398                        true,
20399                        true,
20400                        None,
20401                        window,
20402                        cx,
20403                    );
20404                });
20405            });
20406        });
20407    }
20408
20409    pub fn open_excerpts_in_split(
20410        &mut self,
20411        _: &OpenExcerptsSplit,
20412        window: &mut Window,
20413        cx: &mut Context<Self>,
20414    ) {
20415        self.open_excerpts_common(None, true, window, cx)
20416    }
20417
20418    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20419        self.open_excerpts_common(None, false, window, cx)
20420    }
20421
20422    fn open_excerpts_common(
20423        &mut self,
20424        jump_data: Option<JumpData>,
20425        split: bool,
20426        window: &mut Window,
20427        cx: &mut Context<Self>,
20428    ) {
20429        let Some(workspace) = self.workspace() else {
20430            cx.propagate();
20431            return;
20432        };
20433
20434        if self.buffer.read(cx).is_singleton() {
20435            cx.propagate();
20436            return;
20437        }
20438
20439        let mut new_selections_by_buffer = HashMap::default();
20440        match &jump_data {
20441            Some(JumpData::MultiBufferPoint {
20442                excerpt_id,
20443                position,
20444                anchor,
20445                line_offset_from_top,
20446            }) => {
20447                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20448                if let Some(buffer) = multi_buffer_snapshot
20449                    .buffer_id_for_excerpt(*excerpt_id)
20450                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20451                {
20452                    let buffer_snapshot = buffer.read(cx).snapshot();
20453                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20454                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20455                    } else {
20456                        buffer_snapshot.clip_point(*position, Bias::Left)
20457                    };
20458                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20459                    new_selections_by_buffer.insert(
20460                        buffer,
20461                        (
20462                            vec![jump_to_offset..jump_to_offset],
20463                            Some(*line_offset_from_top),
20464                        ),
20465                    );
20466                }
20467            }
20468            Some(JumpData::MultiBufferRow {
20469                row,
20470                line_offset_from_top,
20471            }) => {
20472                let point = MultiBufferPoint::new(row.0, 0);
20473                if let Some((buffer, buffer_point, _)) =
20474                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20475                {
20476                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20477                    new_selections_by_buffer
20478                        .entry(buffer)
20479                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20480                        .0
20481                        .push(buffer_offset..buffer_offset)
20482                }
20483            }
20484            None => {
20485                let selections = self.selections.all::<usize>(cx);
20486                let multi_buffer = self.buffer.read(cx);
20487                for selection in selections {
20488                    for (snapshot, range, _, anchor) in multi_buffer
20489                        .snapshot(cx)
20490                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20491                    {
20492                        if let Some(anchor) = anchor {
20493                            // selection is in a deleted hunk
20494                            let Some(buffer_id) = anchor.buffer_id else {
20495                                continue;
20496                            };
20497                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20498                                continue;
20499                            };
20500                            let offset = text::ToOffset::to_offset(
20501                                &anchor.text_anchor,
20502                                &buffer_handle.read(cx).snapshot(),
20503                            );
20504                            let range = offset..offset;
20505                            new_selections_by_buffer
20506                                .entry(buffer_handle)
20507                                .or_insert((Vec::new(), None))
20508                                .0
20509                                .push(range)
20510                        } else {
20511                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20512                            else {
20513                                continue;
20514                            };
20515                            new_selections_by_buffer
20516                                .entry(buffer_handle)
20517                                .or_insert((Vec::new(), None))
20518                                .0
20519                                .push(range)
20520                        }
20521                    }
20522                }
20523            }
20524        }
20525
20526        new_selections_by_buffer
20527            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20528
20529        if new_selections_by_buffer.is_empty() {
20530            return;
20531        }
20532
20533        // We defer the pane interaction because we ourselves are a workspace item
20534        // and activating a new item causes the pane to call a method on us reentrantly,
20535        // which panics if we're on the stack.
20536        window.defer(cx, move |window, cx| {
20537            workspace.update(cx, |workspace, cx| {
20538                let pane = if split {
20539                    workspace.adjacent_pane(window, cx)
20540                } else {
20541                    workspace.active_pane().clone()
20542                };
20543
20544                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20545                    let editor = buffer
20546                        .read(cx)
20547                        .file()
20548                        .is_none()
20549                        .then(|| {
20550                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20551                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20552                            // Instead, we try to activate the existing editor in the pane first.
20553                            let (editor, pane_item_index) =
20554                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20555                                    let editor = item.downcast::<Editor>()?;
20556                                    let singleton_buffer =
20557                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20558                                    if singleton_buffer == buffer {
20559                                        Some((editor, i))
20560                                    } else {
20561                                        None
20562                                    }
20563                                })?;
20564                            pane.update(cx, |pane, cx| {
20565                                pane.activate_item(pane_item_index, true, true, window, cx)
20566                            });
20567                            Some(editor)
20568                        })
20569                        .flatten()
20570                        .unwrap_or_else(|| {
20571                            workspace.open_project_item::<Self>(
20572                                pane.clone(),
20573                                buffer,
20574                                true,
20575                                true,
20576                                window,
20577                                cx,
20578                            )
20579                        });
20580
20581                    editor.update(cx, |editor, cx| {
20582                        let autoscroll = match scroll_offset {
20583                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20584                            None => Autoscroll::newest(),
20585                        };
20586                        let nav_history = editor.nav_history.take();
20587                        editor.change_selections(
20588                            SelectionEffects::scroll(autoscroll),
20589                            window,
20590                            cx,
20591                            |s| {
20592                                s.select_ranges(ranges);
20593                            },
20594                        );
20595                        editor.nav_history = nav_history;
20596                    });
20597                }
20598            })
20599        });
20600    }
20601
20602    // For now, don't allow opening excerpts in buffers that aren't backed by
20603    // regular project files.
20604    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20605        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20606    }
20607
20608    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20609        let snapshot = self.buffer.read(cx).read(cx);
20610        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20611        Some(
20612            ranges
20613                .iter()
20614                .map(move |range| {
20615                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20616                })
20617                .collect(),
20618        )
20619    }
20620
20621    fn selection_replacement_ranges(
20622        &self,
20623        range: Range<OffsetUtf16>,
20624        cx: &mut App,
20625    ) -> Vec<Range<OffsetUtf16>> {
20626        let selections = self.selections.all::<OffsetUtf16>(cx);
20627        let newest_selection = selections
20628            .iter()
20629            .max_by_key(|selection| selection.id)
20630            .unwrap();
20631        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20632        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20633        let snapshot = self.buffer.read(cx).read(cx);
20634        selections
20635            .into_iter()
20636            .map(|mut selection| {
20637                selection.start.0 =
20638                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20639                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20640                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20641                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20642            })
20643            .collect()
20644    }
20645
20646    fn report_editor_event(
20647        &self,
20648        reported_event: ReportEditorEvent,
20649        file_extension: Option<String>,
20650        cx: &App,
20651    ) {
20652        if cfg!(any(test, feature = "test-support")) {
20653            return;
20654        }
20655
20656        let Some(project) = &self.project else { return };
20657
20658        // If None, we are in a file without an extension
20659        let file = self
20660            .buffer
20661            .read(cx)
20662            .as_singleton()
20663            .and_then(|b| b.read(cx).file());
20664        let file_extension = file_extension.or(file
20665            .as_ref()
20666            .and_then(|file| Path::new(file.file_name(cx)).extension())
20667            .and_then(|e| e.to_str())
20668            .map(|a| a.to_string()));
20669
20670        let vim_mode = vim_enabled(cx);
20671
20672        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20673        let copilot_enabled = edit_predictions_provider
20674            == language::language_settings::EditPredictionProvider::Copilot;
20675        let copilot_enabled_for_language = self
20676            .buffer
20677            .read(cx)
20678            .language_settings(cx)
20679            .show_edit_predictions;
20680
20681        let project = project.read(cx);
20682        let event_type = reported_event.event_type();
20683
20684        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20685            telemetry::event!(
20686                event_type,
20687                type = if auto_saved {"autosave"} else {"manual"},
20688                file_extension,
20689                vim_mode,
20690                copilot_enabled,
20691                copilot_enabled_for_language,
20692                edit_predictions_provider,
20693                is_via_ssh = project.is_via_ssh(),
20694            );
20695        } else {
20696            telemetry::event!(
20697                event_type,
20698                file_extension,
20699                vim_mode,
20700                copilot_enabled,
20701                copilot_enabled_for_language,
20702                edit_predictions_provider,
20703                is_via_ssh = project.is_via_ssh(),
20704            );
20705        };
20706    }
20707
20708    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20709    /// with each line being an array of {text, highlight} objects.
20710    fn copy_highlight_json(
20711        &mut self,
20712        _: &CopyHighlightJson,
20713        window: &mut Window,
20714        cx: &mut Context<Self>,
20715    ) {
20716        #[derive(Serialize)]
20717        struct Chunk<'a> {
20718            text: String,
20719            highlight: Option<&'a str>,
20720        }
20721
20722        let snapshot = self.buffer.read(cx).snapshot(cx);
20723        let range = self
20724            .selected_text_range(false, window, cx)
20725            .and_then(|selection| {
20726                if selection.range.is_empty() {
20727                    None
20728                } else {
20729                    Some(selection.range)
20730                }
20731            })
20732            .unwrap_or_else(|| 0..snapshot.len());
20733
20734        let chunks = snapshot.chunks(range, true);
20735        let mut lines = Vec::new();
20736        let mut line: VecDeque<Chunk> = VecDeque::new();
20737
20738        let Some(style) = self.style.as_ref() else {
20739            return;
20740        };
20741
20742        for chunk in chunks {
20743            let highlight = chunk
20744                .syntax_highlight_id
20745                .and_then(|id| id.name(&style.syntax));
20746            let mut chunk_lines = chunk.text.split('\n').peekable();
20747            while let Some(text) = chunk_lines.next() {
20748                let mut merged_with_last_token = false;
20749                if let Some(last_token) = line.back_mut()
20750                    && last_token.highlight == highlight
20751                {
20752                    last_token.text.push_str(text);
20753                    merged_with_last_token = true;
20754                }
20755
20756                if !merged_with_last_token {
20757                    line.push_back(Chunk {
20758                        text: text.into(),
20759                        highlight,
20760                    });
20761                }
20762
20763                if chunk_lines.peek().is_some() {
20764                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20765                        line.pop_front();
20766                    }
20767                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20768                        line.pop_back();
20769                    }
20770
20771                    lines.push(mem::take(&mut line));
20772                }
20773            }
20774        }
20775
20776        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20777            return;
20778        };
20779        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20780    }
20781
20782    pub fn open_context_menu(
20783        &mut self,
20784        _: &OpenContextMenu,
20785        window: &mut Window,
20786        cx: &mut Context<Self>,
20787    ) {
20788        self.request_autoscroll(Autoscroll::newest(), cx);
20789        let position = self.selections.newest_display(cx).start;
20790        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20791    }
20792
20793    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20794        &self.inlay_hint_cache
20795    }
20796
20797    pub fn replay_insert_event(
20798        &mut self,
20799        text: &str,
20800        relative_utf16_range: Option<Range<isize>>,
20801        window: &mut Window,
20802        cx: &mut Context<Self>,
20803    ) {
20804        if !self.input_enabled {
20805            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20806            return;
20807        }
20808        if let Some(relative_utf16_range) = relative_utf16_range {
20809            let selections = self.selections.all::<OffsetUtf16>(cx);
20810            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20811                let new_ranges = selections.into_iter().map(|range| {
20812                    let start = OffsetUtf16(
20813                        range
20814                            .head()
20815                            .0
20816                            .saturating_add_signed(relative_utf16_range.start),
20817                    );
20818                    let end = OffsetUtf16(
20819                        range
20820                            .head()
20821                            .0
20822                            .saturating_add_signed(relative_utf16_range.end),
20823                    );
20824                    start..end
20825                });
20826                s.select_ranges(new_ranges);
20827            });
20828        }
20829
20830        self.handle_input(text, window, cx);
20831    }
20832
20833    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20834        let Some(provider) = self.semantics_provider.as_ref() else {
20835            return false;
20836        };
20837
20838        let mut supports = false;
20839        self.buffer().update(cx, |this, cx| {
20840            this.for_each_buffer(|buffer| {
20841                supports |= provider.supports_inlay_hints(buffer, cx);
20842            });
20843        });
20844
20845        supports
20846    }
20847
20848    pub fn is_focused(&self, window: &Window) -> bool {
20849        self.focus_handle.is_focused(window)
20850    }
20851
20852    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20853        cx.emit(EditorEvent::Focused);
20854
20855        if let Some(descendant) = self
20856            .last_focused_descendant
20857            .take()
20858            .and_then(|descendant| descendant.upgrade())
20859        {
20860            window.focus(&descendant);
20861        } else {
20862            if let Some(blame) = self.blame.as_ref() {
20863                blame.update(cx, GitBlame::focus)
20864            }
20865
20866            self.blink_manager.update(cx, BlinkManager::enable);
20867            self.show_cursor_names(window, cx);
20868            self.buffer.update(cx, |buffer, cx| {
20869                buffer.finalize_last_transaction(cx);
20870                if self.leader_id.is_none() {
20871                    buffer.set_active_selections(
20872                        &self.selections.disjoint_anchors(),
20873                        self.selections.line_mode,
20874                        self.cursor_shape,
20875                        cx,
20876                    );
20877                }
20878            });
20879        }
20880    }
20881
20882    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20883        cx.emit(EditorEvent::FocusedIn)
20884    }
20885
20886    fn handle_focus_out(
20887        &mut self,
20888        event: FocusOutEvent,
20889        _window: &mut Window,
20890        cx: &mut Context<Self>,
20891    ) {
20892        if event.blurred != self.focus_handle {
20893            self.last_focused_descendant = Some(event.blurred);
20894        }
20895        self.selection_drag_state = SelectionDragState::None;
20896        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20897    }
20898
20899    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20900        self.blink_manager.update(cx, BlinkManager::disable);
20901        self.buffer
20902            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20903
20904        if let Some(blame) = self.blame.as_ref() {
20905            blame.update(cx, GitBlame::blur)
20906        }
20907        if !self.hover_state.focused(window, cx) {
20908            hide_hover(self, cx);
20909        }
20910        if !self
20911            .context_menu
20912            .borrow()
20913            .as_ref()
20914            .is_some_and(|context_menu| context_menu.focused(window, cx))
20915        {
20916            self.hide_context_menu(window, cx);
20917        }
20918        self.discard_edit_prediction(false, cx);
20919        cx.emit(EditorEvent::Blurred);
20920        cx.notify();
20921    }
20922
20923    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20924        let mut pending: String = window
20925            .pending_input_keystrokes()
20926            .into_iter()
20927            .flatten()
20928            .filter_map(|keystroke| {
20929                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20930                    keystroke.key_char.clone()
20931                } else {
20932                    None
20933                }
20934            })
20935            .collect();
20936
20937        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20938            pending = "".to_string();
20939        }
20940
20941        let existing_pending = self
20942            .text_highlights::<PendingInput>(cx)
20943            .map(|(_, ranges)| ranges.to_vec());
20944        if existing_pending.is_none() && pending.is_empty() {
20945            return;
20946        }
20947        let transaction =
20948            self.transact(window, cx, |this, window, cx| {
20949                let selections = this.selections.all::<usize>(cx);
20950                let edits = selections
20951                    .iter()
20952                    .map(|selection| (selection.end..selection.end, pending.clone()));
20953                this.edit(edits, cx);
20954                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20955                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20956                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20957                    }));
20958                });
20959                if let Some(existing_ranges) = existing_pending {
20960                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20961                    this.edit(edits, cx);
20962                }
20963            });
20964
20965        let snapshot = self.snapshot(window, cx);
20966        let ranges = self
20967            .selections
20968            .all::<usize>(cx)
20969            .into_iter()
20970            .map(|selection| {
20971                snapshot.buffer_snapshot.anchor_after(selection.end)
20972                    ..snapshot
20973                        .buffer_snapshot
20974                        .anchor_before(selection.end + pending.len())
20975            })
20976            .collect();
20977
20978        if pending.is_empty() {
20979            self.clear_highlights::<PendingInput>(cx);
20980        } else {
20981            self.highlight_text::<PendingInput>(
20982                ranges,
20983                HighlightStyle {
20984                    underline: Some(UnderlineStyle {
20985                        thickness: px(1.),
20986                        color: None,
20987                        wavy: false,
20988                    }),
20989                    ..Default::default()
20990                },
20991                cx,
20992            );
20993        }
20994
20995        self.ime_transaction = self.ime_transaction.or(transaction);
20996        if let Some(transaction) = self.ime_transaction {
20997            self.buffer.update(cx, |buffer, cx| {
20998                buffer.group_until_transaction(transaction, cx);
20999            });
21000        }
21001
21002        if self.text_highlights::<PendingInput>(cx).is_none() {
21003            self.ime_transaction.take();
21004        }
21005    }
21006
21007    pub fn register_action_renderer(
21008        &mut self,
21009        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21010    ) -> Subscription {
21011        let id = self.next_editor_action_id.post_inc();
21012        self.editor_actions
21013            .borrow_mut()
21014            .insert(id, Box::new(listener));
21015
21016        let editor_actions = self.editor_actions.clone();
21017        Subscription::new(move || {
21018            editor_actions.borrow_mut().remove(&id);
21019        })
21020    }
21021
21022    pub fn register_action<A: Action>(
21023        &mut self,
21024        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21025    ) -> Subscription {
21026        let id = self.next_editor_action_id.post_inc();
21027        let listener = Arc::new(listener);
21028        self.editor_actions.borrow_mut().insert(
21029            id,
21030            Box::new(move |_, window, _| {
21031                let listener = listener.clone();
21032                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21033                    let action = action.downcast_ref().unwrap();
21034                    if phase == DispatchPhase::Bubble {
21035                        listener(action, window, cx)
21036                    }
21037                })
21038            }),
21039        );
21040
21041        let editor_actions = self.editor_actions.clone();
21042        Subscription::new(move || {
21043            editor_actions.borrow_mut().remove(&id);
21044        })
21045    }
21046
21047    pub fn file_header_size(&self) -> u32 {
21048        FILE_HEADER_HEIGHT
21049    }
21050
21051    pub fn restore(
21052        &mut self,
21053        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21054        window: &mut Window,
21055        cx: &mut Context<Self>,
21056    ) {
21057        let workspace = self.workspace();
21058        let project = self.project();
21059        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21060            let mut tasks = Vec::new();
21061            for (buffer_id, changes) in revert_changes {
21062                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21063                    buffer.update(cx, |buffer, cx| {
21064                        buffer.edit(
21065                            changes
21066                                .into_iter()
21067                                .map(|(range, text)| (range, text.to_string())),
21068                            None,
21069                            cx,
21070                        );
21071                    });
21072
21073                    if let Some(project) =
21074                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21075                    {
21076                        project.update(cx, |project, cx| {
21077                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21078                        })
21079                    }
21080                }
21081            }
21082            tasks
21083        });
21084        cx.spawn_in(window, async move |_, cx| {
21085            for (buffer, task) in save_tasks {
21086                let result = task.await;
21087                if result.is_err() {
21088                    let Some(path) = buffer
21089                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21090                        .ok()
21091                    else {
21092                        continue;
21093                    };
21094                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21095                        let Some(task) = cx
21096                            .update_window_entity(workspace, |workspace, window, cx| {
21097                                workspace
21098                                    .open_path_preview(path, None, false, false, false, window, cx)
21099                            })
21100                            .ok()
21101                        else {
21102                            continue;
21103                        };
21104                        task.await.log_err();
21105                    }
21106                }
21107            }
21108        })
21109        .detach();
21110        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21111            selections.refresh()
21112        });
21113    }
21114
21115    pub fn to_pixel_point(
21116        &self,
21117        source: multi_buffer::Anchor,
21118        editor_snapshot: &EditorSnapshot,
21119        window: &mut Window,
21120    ) -> Option<gpui::Point<Pixels>> {
21121        let source_point = source.to_display_point(editor_snapshot);
21122        self.display_to_pixel_point(source_point, editor_snapshot, window)
21123    }
21124
21125    pub fn display_to_pixel_point(
21126        &self,
21127        source: DisplayPoint,
21128        editor_snapshot: &EditorSnapshot,
21129        window: &mut Window,
21130    ) -> Option<gpui::Point<Pixels>> {
21131        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21132        let text_layout_details = self.text_layout_details(window);
21133        let scroll_top = text_layout_details
21134            .scroll_anchor
21135            .scroll_position(editor_snapshot)
21136            .y;
21137
21138        if source.row().as_f32() < scroll_top.floor() {
21139            return None;
21140        }
21141        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21142        let source_y = line_height * (source.row().as_f32() - scroll_top);
21143        Some(gpui::Point::new(source_x, source_y))
21144    }
21145
21146    pub fn has_visible_completions_menu(&self) -> bool {
21147        !self.edit_prediction_preview_is_active()
21148            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21149                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21150            })
21151    }
21152
21153    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21154        if self.mode.is_minimap() {
21155            return;
21156        }
21157        self.addons
21158            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21159    }
21160
21161    pub fn unregister_addon<T: Addon>(&mut self) {
21162        self.addons.remove(&std::any::TypeId::of::<T>());
21163    }
21164
21165    pub fn addon<T: Addon>(&self) -> Option<&T> {
21166        let type_id = std::any::TypeId::of::<T>();
21167        self.addons
21168            .get(&type_id)
21169            .and_then(|item| item.to_any().downcast_ref::<T>())
21170    }
21171
21172    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21173        let type_id = std::any::TypeId::of::<T>();
21174        self.addons
21175            .get_mut(&type_id)
21176            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21177    }
21178
21179    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21180        let text_layout_details = self.text_layout_details(window);
21181        let style = &text_layout_details.editor_style;
21182        let font_id = window.text_system().resolve_font(&style.text.font());
21183        let font_size = style.text.font_size.to_pixels(window.rem_size());
21184        let line_height = style.text.line_height_in_pixels(window.rem_size());
21185        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21186        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21187
21188        CharacterDimensions {
21189            em_width,
21190            em_advance,
21191            line_height,
21192        }
21193    }
21194
21195    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21196        self.load_diff_task.clone()
21197    }
21198
21199    fn read_metadata_from_db(
21200        &mut self,
21201        item_id: u64,
21202        workspace_id: WorkspaceId,
21203        window: &mut Window,
21204        cx: &mut Context<Editor>,
21205    ) {
21206        if self.is_singleton(cx)
21207            && !self.mode.is_minimap()
21208            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21209        {
21210            let buffer_snapshot = OnceCell::new();
21211
21212            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21213                && !folds.is_empty()
21214            {
21215                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21216                self.fold_ranges(
21217                    folds
21218                        .into_iter()
21219                        .map(|(start, end)| {
21220                            snapshot.clip_offset(start, Bias::Left)
21221                                ..snapshot.clip_offset(end, Bias::Right)
21222                        })
21223                        .collect(),
21224                    false,
21225                    window,
21226                    cx,
21227                );
21228            }
21229
21230            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21231                && !selections.is_empty()
21232            {
21233                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21234                // skip adding the initial selection to selection history
21235                self.selection_history.mode = SelectionHistoryMode::Skipping;
21236                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21237                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21238                        snapshot.clip_offset(start, Bias::Left)
21239                            ..snapshot.clip_offset(end, Bias::Right)
21240                    }));
21241                });
21242                self.selection_history.mode = SelectionHistoryMode::Normal;
21243            };
21244        }
21245
21246        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21247    }
21248
21249    fn update_lsp_data(
21250        &mut self,
21251        ignore_cache: bool,
21252        for_buffer: Option<BufferId>,
21253        window: &mut Window,
21254        cx: &mut Context<'_, Self>,
21255    ) {
21256        self.pull_diagnostics(for_buffer, window, cx);
21257        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21258    }
21259}
21260
21261fn vim_enabled(cx: &App) -> bool {
21262    cx.global::<SettingsStore>()
21263        .raw_user_settings()
21264        .get("vim_mode")
21265        == Some(&serde_json::Value::Bool(true))
21266}
21267
21268fn process_completion_for_edit(
21269    completion: &Completion,
21270    intent: CompletionIntent,
21271    buffer: &Entity<Buffer>,
21272    cursor_position: &text::Anchor,
21273    cx: &mut Context<Editor>,
21274) -> CompletionEdit {
21275    let buffer = buffer.read(cx);
21276    let buffer_snapshot = buffer.snapshot();
21277    let (snippet, new_text) = if completion.is_snippet() {
21278        // Workaround for typescript language server issues so that methods don't expand within
21279        // strings and functions with type expressions. The previous point is used because the query
21280        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21281        let mut snippet_source = completion.new_text.clone();
21282        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21283        previous_point.column = previous_point.column.saturating_sub(1);
21284        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21285            && scope.prefers_label_for_snippet_in_completion()
21286            && let Some(label) = completion.label()
21287            && matches!(
21288                completion.kind(),
21289                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21290            )
21291        {
21292            snippet_source = label;
21293        }
21294        match Snippet::parse(&snippet_source).log_err() {
21295            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21296            None => (None, completion.new_text.clone()),
21297        }
21298    } else {
21299        (None, completion.new_text.clone())
21300    };
21301
21302    let mut range_to_replace = {
21303        let replace_range = &completion.replace_range;
21304        if let CompletionSource::Lsp {
21305            insert_range: Some(insert_range),
21306            ..
21307        } = &completion.source
21308        {
21309            debug_assert_eq!(
21310                insert_range.start, replace_range.start,
21311                "insert_range and replace_range should start at the same position"
21312            );
21313            debug_assert!(
21314                insert_range
21315                    .start
21316                    .cmp(cursor_position, &buffer_snapshot)
21317                    .is_le(),
21318                "insert_range should start before or at cursor position"
21319            );
21320            debug_assert!(
21321                replace_range
21322                    .start
21323                    .cmp(cursor_position, &buffer_snapshot)
21324                    .is_le(),
21325                "replace_range should start before or at cursor position"
21326            );
21327
21328            let should_replace = match intent {
21329                CompletionIntent::CompleteWithInsert => false,
21330                CompletionIntent::CompleteWithReplace => true,
21331                CompletionIntent::Complete | CompletionIntent::Compose => {
21332                    let insert_mode =
21333                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21334                            .completions
21335                            .lsp_insert_mode;
21336                    match insert_mode {
21337                        LspInsertMode::Insert => false,
21338                        LspInsertMode::Replace => true,
21339                        LspInsertMode::ReplaceSubsequence => {
21340                            let mut text_to_replace = buffer.chars_for_range(
21341                                buffer.anchor_before(replace_range.start)
21342                                    ..buffer.anchor_after(replace_range.end),
21343                            );
21344                            let mut current_needle = text_to_replace.next();
21345                            for haystack_ch in completion.label.text.chars() {
21346                                if let Some(needle_ch) = current_needle
21347                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21348                                {
21349                                    current_needle = text_to_replace.next();
21350                                }
21351                            }
21352                            current_needle.is_none()
21353                        }
21354                        LspInsertMode::ReplaceSuffix => {
21355                            if replace_range
21356                                .end
21357                                .cmp(cursor_position, &buffer_snapshot)
21358                                .is_gt()
21359                            {
21360                                let range_after_cursor = *cursor_position..replace_range.end;
21361                                let text_after_cursor = buffer
21362                                    .text_for_range(
21363                                        buffer.anchor_before(range_after_cursor.start)
21364                                            ..buffer.anchor_after(range_after_cursor.end),
21365                                    )
21366                                    .collect::<String>()
21367                                    .to_ascii_lowercase();
21368                                completion
21369                                    .label
21370                                    .text
21371                                    .to_ascii_lowercase()
21372                                    .ends_with(&text_after_cursor)
21373                            } else {
21374                                true
21375                            }
21376                        }
21377                    }
21378                }
21379            };
21380
21381            if should_replace {
21382                replace_range.clone()
21383            } else {
21384                insert_range.clone()
21385            }
21386        } else {
21387            replace_range.clone()
21388        }
21389    };
21390
21391    if range_to_replace
21392        .end
21393        .cmp(cursor_position, &buffer_snapshot)
21394        .is_lt()
21395    {
21396        range_to_replace.end = *cursor_position;
21397    }
21398
21399    CompletionEdit {
21400        new_text,
21401        replace_range: range_to_replace.to_offset(buffer),
21402        snippet,
21403    }
21404}
21405
21406struct CompletionEdit {
21407    new_text: String,
21408    replace_range: Range<usize>,
21409    snippet: Option<Snippet>,
21410}
21411
21412fn insert_extra_newline_brackets(
21413    buffer: &MultiBufferSnapshot,
21414    range: Range<usize>,
21415    language: &language::LanguageScope,
21416) -> bool {
21417    let leading_whitespace_len = buffer
21418        .reversed_chars_at(range.start)
21419        .take_while(|c| c.is_whitespace() && *c != '\n')
21420        .map(|c| c.len_utf8())
21421        .sum::<usize>();
21422    let trailing_whitespace_len = buffer
21423        .chars_at(range.end)
21424        .take_while(|c| c.is_whitespace() && *c != '\n')
21425        .map(|c| c.len_utf8())
21426        .sum::<usize>();
21427    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21428
21429    language.brackets().any(|(pair, enabled)| {
21430        let pair_start = pair.start.trim_end();
21431        let pair_end = pair.end.trim_start();
21432
21433        enabled
21434            && pair.newline
21435            && buffer.contains_str_at(range.end, pair_end)
21436            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21437    })
21438}
21439
21440fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21441    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21442        [(buffer, range, _)] => (*buffer, range.clone()),
21443        _ => return false,
21444    };
21445    let pair = {
21446        let mut result: Option<BracketMatch> = None;
21447
21448        for pair in buffer
21449            .all_bracket_ranges(range.clone())
21450            .filter(move |pair| {
21451                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21452            })
21453        {
21454            let len = pair.close_range.end - pair.open_range.start;
21455
21456            if let Some(existing) = &result {
21457                let existing_len = existing.close_range.end - existing.open_range.start;
21458                if len > existing_len {
21459                    continue;
21460                }
21461            }
21462
21463            result = Some(pair);
21464        }
21465
21466        result
21467    };
21468    let Some(pair) = pair else {
21469        return false;
21470    };
21471    pair.newline_only
21472        && buffer
21473            .chars_for_range(pair.open_range.end..range.start)
21474            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21475            .all(|c| c.is_whitespace() && c != '\n')
21476}
21477
21478fn update_uncommitted_diff_for_buffer(
21479    editor: Entity<Editor>,
21480    project: &Entity<Project>,
21481    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21482    buffer: Entity<MultiBuffer>,
21483    cx: &mut App,
21484) -> Task<()> {
21485    let mut tasks = Vec::new();
21486    project.update(cx, |project, cx| {
21487        for buffer in buffers {
21488            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21489                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21490            }
21491        }
21492    });
21493    cx.spawn(async move |cx| {
21494        let diffs = future::join_all(tasks).await;
21495        if editor
21496            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21497            .unwrap_or(false)
21498        {
21499            return;
21500        }
21501
21502        buffer
21503            .update(cx, |buffer, cx| {
21504                for diff in diffs.into_iter().flatten() {
21505                    buffer.add_diff(diff, cx);
21506                }
21507            })
21508            .ok();
21509    })
21510}
21511
21512fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21513    let tab_size = tab_size.get() as usize;
21514    let mut width = offset;
21515
21516    for ch in text.chars() {
21517        width += if ch == '\t' {
21518            tab_size - (width % tab_size)
21519        } else {
21520            1
21521        };
21522    }
21523
21524    width - offset
21525}
21526
21527#[cfg(test)]
21528mod tests {
21529    use super::*;
21530
21531    #[test]
21532    fn test_string_size_with_expanded_tabs() {
21533        let nz = |val| NonZeroU32::new(val).unwrap();
21534        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21535        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21536        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21537        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21538        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21539        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21540        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21541        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21542    }
21543}
21544
21545/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21546struct WordBreakingTokenizer<'a> {
21547    input: &'a str,
21548}
21549
21550impl<'a> WordBreakingTokenizer<'a> {
21551    fn new(input: &'a str) -> Self {
21552        Self { input }
21553    }
21554}
21555
21556fn is_char_ideographic(ch: char) -> bool {
21557    use unicode_script::Script::*;
21558    use unicode_script::UnicodeScript;
21559    matches!(ch.script(), Han | Tangut | Yi)
21560}
21561
21562fn is_grapheme_ideographic(text: &str) -> bool {
21563    text.chars().any(is_char_ideographic)
21564}
21565
21566fn is_grapheme_whitespace(text: &str) -> bool {
21567    text.chars().any(|x| x.is_whitespace())
21568}
21569
21570fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21571    text.chars()
21572        .next()
21573        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21574}
21575
21576#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21577enum WordBreakToken<'a> {
21578    Word { token: &'a str, grapheme_len: usize },
21579    InlineWhitespace { token: &'a str, grapheme_len: usize },
21580    Newline,
21581}
21582
21583impl<'a> Iterator for WordBreakingTokenizer<'a> {
21584    /// Yields a span, the count of graphemes in the token, and whether it was
21585    /// whitespace. Note that it also breaks at word boundaries.
21586    type Item = WordBreakToken<'a>;
21587
21588    fn next(&mut self) -> Option<Self::Item> {
21589        use unicode_segmentation::UnicodeSegmentation;
21590        if self.input.is_empty() {
21591            return None;
21592        }
21593
21594        let mut iter = self.input.graphemes(true).peekable();
21595        let mut offset = 0;
21596        let mut grapheme_len = 0;
21597        if let Some(first_grapheme) = iter.next() {
21598            let is_newline = first_grapheme == "\n";
21599            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21600            offset += first_grapheme.len();
21601            grapheme_len += 1;
21602            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21603                if let Some(grapheme) = iter.peek().copied()
21604                    && should_stay_with_preceding_ideograph(grapheme)
21605                {
21606                    offset += grapheme.len();
21607                    grapheme_len += 1;
21608                }
21609            } else {
21610                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21611                let mut next_word_bound = words.peek().copied();
21612                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21613                    next_word_bound = words.next();
21614                }
21615                while let Some(grapheme) = iter.peek().copied() {
21616                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21617                        break;
21618                    };
21619                    if is_grapheme_whitespace(grapheme) != is_whitespace
21620                        || (grapheme == "\n") != is_newline
21621                    {
21622                        break;
21623                    };
21624                    offset += grapheme.len();
21625                    grapheme_len += 1;
21626                    iter.next();
21627                }
21628            }
21629            let token = &self.input[..offset];
21630            self.input = &self.input[offset..];
21631            if token == "\n" {
21632                Some(WordBreakToken::Newline)
21633            } else if is_whitespace {
21634                Some(WordBreakToken::InlineWhitespace {
21635                    token,
21636                    grapheme_len,
21637                })
21638            } else {
21639                Some(WordBreakToken::Word {
21640                    token,
21641                    grapheme_len,
21642                })
21643            }
21644        } else {
21645            None
21646        }
21647    }
21648}
21649
21650#[test]
21651fn test_word_breaking_tokenizer() {
21652    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21653        ("", &[]),
21654        ("  ", &[whitespace("  ", 2)]),
21655        ("Ʒ", &[word("Ʒ", 1)]),
21656        ("Ǽ", &[word("Ǽ", 1)]),
21657        ("", &[word("", 1)]),
21658        ("⋑⋑", &[word("⋑⋑", 2)]),
21659        (
21660            "原理,进而",
21661            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21662        ),
21663        (
21664            "hello world",
21665            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21666        ),
21667        (
21668            "hello, world",
21669            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21670        ),
21671        (
21672            "  hello world",
21673            &[
21674                whitespace("  ", 2),
21675                word("hello", 5),
21676                whitespace(" ", 1),
21677                word("world", 5),
21678            ],
21679        ),
21680        (
21681            "这是什么 \n 钢笔",
21682            &[
21683                word("", 1),
21684                word("", 1),
21685                word("", 1),
21686                word("", 1),
21687                whitespace(" ", 1),
21688                newline(),
21689                whitespace(" ", 1),
21690                word("", 1),
21691                word("", 1),
21692            ],
21693        ),
21694        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21695    ];
21696
21697    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21698        WordBreakToken::Word {
21699            token,
21700            grapheme_len,
21701        }
21702    }
21703
21704    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21705        WordBreakToken::InlineWhitespace {
21706            token,
21707            grapheme_len,
21708        }
21709    }
21710
21711    fn newline() -> WordBreakToken<'static> {
21712        WordBreakToken::Newline
21713    }
21714
21715    for (input, result) in tests {
21716        assert_eq!(
21717            WordBreakingTokenizer::new(input)
21718                .collect::<Vec<_>>()
21719                .as_slice(),
21720            *result,
21721        );
21722    }
21723}
21724
21725fn wrap_with_prefix(
21726    first_line_prefix: String,
21727    subsequent_lines_prefix: String,
21728    unwrapped_text: String,
21729    wrap_column: usize,
21730    tab_size: NonZeroU32,
21731    preserve_existing_whitespace: bool,
21732) -> String {
21733    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21734    let subsequent_lines_prefix_len =
21735        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21736    let mut wrapped_text = String::new();
21737    let mut current_line = first_line_prefix.clone();
21738    let mut is_first_line = true;
21739
21740    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21741    let mut current_line_len = first_line_prefix_len;
21742    let mut in_whitespace = false;
21743    for token in tokenizer {
21744        let have_preceding_whitespace = in_whitespace;
21745        match token {
21746            WordBreakToken::Word {
21747                token,
21748                grapheme_len,
21749            } => {
21750                in_whitespace = false;
21751                let current_prefix_len = if is_first_line {
21752                    first_line_prefix_len
21753                } else {
21754                    subsequent_lines_prefix_len
21755                };
21756                if current_line_len + grapheme_len > wrap_column
21757                    && current_line_len != current_prefix_len
21758                {
21759                    wrapped_text.push_str(current_line.trim_end());
21760                    wrapped_text.push('\n');
21761                    is_first_line = false;
21762                    current_line = subsequent_lines_prefix.clone();
21763                    current_line_len = subsequent_lines_prefix_len;
21764                }
21765                current_line.push_str(token);
21766                current_line_len += grapheme_len;
21767            }
21768            WordBreakToken::InlineWhitespace {
21769                mut token,
21770                mut grapheme_len,
21771            } => {
21772                in_whitespace = true;
21773                if have_preceding_whitespace && !preserve_existing_whitespace {
21774                    continue;
21775                }
21776                if !preserve_existing_whitespace {
21777                    token = " ";
21778                    grapheme_len = 1;
21779                }
21780                let current_prefix_len = if is_first_line {
21781                    first_line_prefix_len
21782                } else {
21783                    subsequent_lines_prefix_len
21784                };
21785                if current_line_len + grapheme_len > wrap_column {
21786                    wrapped_text.push_str(current_line.trim_end());
21787                    wrapped_text.push('\n');
21788                    is_first_line = false;
21789                    current_line = subsequent_lines_prefix.clone();
21790                    current_line_len = subsequent_lines_prefix_len;
21791                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21792                    current_line.push_str(token);
21793                    current_line_len += grapheme_len;
21794                }
21795            }
21796            WordBreakToken::Newline => {
21797                in_whitespace = true;
21798                let current_prefix_len = if is_first_line {
21799                    first_line_prefix_len
21800                } else {
21801                    subsequent_lines_prefix_len
21802                };
21803                if preserve_existing_whitespace {
21804                    wrapped_text.push_str(current_line.trim_end());
21805                    wrapped_text.push('\n');
21806                    is_first_line = false;
21807                    current_line = subsequent_lines_prefix.clone();
21808                    current_line_len = subsequent_lines_prefix_len;
21809                } else if have_preceding_whitespace {
21810                    continue;
21811                } else if current_line_len + 1 > wrap_column
21812                    && current_line_len != current_prefix_len
21813                {
21814                    wrapped_text.push_str(current_line.trim_end());
21815                    wrapped_text.push('\n');
21816                    is_first_line = false;
21817                    current_line = subsequent_lines_prefix.clone();
21818                    current_line_len = subsequent_lines_prefix_len;
21819                } else if current_line_len != current_prefix_len {
21820                    current_line.push(' ');
21821                    current_line_len += 1;
21822                }
21823            }
21824        }
21825    }
21826
21827    if !current_line.is_empty() {
21828        wrapped_text.push_str(&current_line);
21829    }
21830    wrapped_text
21831}
21832
21833#[test]
21834fn test_wrap_with_prefix() {
21835    assert_eq!(
21836        wrap_with_prefix(
21837            "# ".to_string(),
21838            "# ".to_string(),
21839            "abcdefg".to_string(),
21840            4,
21841            NonZeroU32::new(4).unwrap(),
21842            false,
21843        ),
21844        "# abcdefg"
21845    );
21846    assert_eq!(
21847        wrap_with_prefix(
21848            "".to_string(),
21849            "".to_string(),
21850            "\thello world".to_string(),
21851            8,
21852            NonZeroU32::new(4).unwrap(),
21853            false,
21854        ),
21855        "hello\nworld"
21856    );
21857    assert_eq!(
21858        wrap_with_prefix(
21859            "// ".to_string(),
21860            "// ".to_string(),
21861            "xx \nyy zz aa bb cc".to_string(),
21862            12,
21863            NonZeroU32::new(4).unwrap(),
21864            false,
21865        ),
21866        "// xx yy zz\n// aa bb cc"
21867    );
21868    assert_eq!(
21869        wrap_with_prefix(
21870            String::new(),
21871            String::new(),
21872            "这是什么 \n 钢笔".to_string(),
21873            3,
21874            NonZeroU32::new(4).unwrap(),
21875            false,
21876        ),
21877        "这是什\n么 钢\n"
21878    );
21879}
21880
21881pub trait CollaborationHub {
21882    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21883    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21884    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21885}
21886
21887impl CollaborationHub for Entity<Project> {
21888    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21889        self.read(cx).collaborators()
21890    }
21891
21892    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21893        self.read(cx).user_store().read(cx).participant_indices()
21894    }
21895
21896    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21897        let this = self.read(cx);
21898        let user_ids = this.collaborators().values().map(|c| c.user_id);
21899        this.user_store().read(cx).participant_names(user_ids, cx)
21900    }
21901}
21902
21903pub trait SemanticsProvider {
21904    fn hover(
21905        &self,
21906        buffer: &Entity<Buffer>,
21907        position: text::Anchor,
21908        cx: &mut App,
21909    ) -> Option<Task<Vec<project::Hover>>>;
21910
21911    fn inline_values(
21912        &self,
21913        buffer_handle: Entity<Buffer>,
21914        range: Range<text::Anchor>,
21915        cx: &mut App,
21916    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21917
21918    fn inlay_hints(
21919        &self,
21920        buffer_handle: Entity<Buffer>,
21921        range: Range<text::Anchor>,
21922        cx: &mut App,
21923    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21924
21925    fn resolve_inlay_hint(
21926        &self,
21927        hint: InlayHint,
21928        buffer_handle: Entity<Buffer>,
21929        server_id: LanguageServerId,
21930        cx: &mut App,
21931    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21932
21933    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21934
21935    fn document_highlights(
21936        &self,
21937        buffer: &Entity<Buffer>,
21938        position: text::Anchor,
21939        cx: &mut App,
21940    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21941
21942    fn definitions(
21943        &self,
21944        buffer: &Entity<Buffer>,
21945        position: text::Anchor,
21946        kind: GotoDefinitionKind,
21947        cx: &mut App,
21948    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21949
21950    fn range_for_rename(
21951        &self,
21952        buffer: &Entity<Buffer>,
21953        position: text::Anchor,
21954        cx: &mut App,
21955    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21956
21957    fn perform_rename(
21958        &self,
21959        buffer: &Entity<Buffer>,
21960        position: text::Anchor,
21961        new_name: String,
21962        cx: &mut App,
21963    ) -> Option<Task<Result<ProjectTransaction>>>;
21964}
21965
21966pub trait CompletionProvider {
21967    fn completions(
21968        &self,
21969        excerpt_id: ExcerptId,
21970        buffer: &Entity<Buffer>,
21971        buffer_position: text::Anchor,
21972        trigger: CompletionContext,
21973        window: &mut Window,
21974        cx: &mut Context<Editor>,
21975    ) -> Task<Result<Vec<CompletionResponse>>>;
21976
21977    fn resolve_completions(
21978        &self,
21979        _buffer: Entity<Buffer>,
21980        _completion_indices: Vec<usize>,
21981        _completions: Rc<RefCell<Box<[Completion]>>>,
21982        _cx: &mut Context<Editor>,
21983    ) -> Task<Result<bool>> {
21984        Task::ready(Ok(false))
21985    }
21986
21987    fn apply_additional_edits_for_completion(
21988        &self,
21989        _buffer: Entity<Buffer>,
21990        _completions: Rc<RefCell<Box<[Completion]>>>,
21991        _completion_index: usize,
21992        _push_to_history: bool,
21993        _cx: &mut Context<Editor>,
21994    ) -> Task<Result<Option<language::Transaction>>> {
21995        Task::ready(Ok(None))
21996    }
21997
21998    fn is_completion_trigger(
21999        &self,
22000        buffer: &Entity<Buffer>,
22001        position: language::Anchor,
22002        text: &str,
22003        trigger_in_words: bool,
22004        menu_is_open: bool,
22005        cx: &mut Context<Editor>,
22006    ) -> bool;
22007
22008    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22009
22010    fn sort_completions(&self) -> bool {
22011        true
22012    }
22013
22014    fn filter_completions(&self) -> bool {
22015        true
22016    }
22017}
22018
22019pub trait CodeActionProvider {
22020    fn id(&self) -> Arc<str>;
22021
22022    fn code_actions(
22023        &self,
22024        buffer: &Entity<Buffer>,
22025        range: Range<text::Anchor>,
22026        window: &mut Window,
22027        cx: &mut App,
22028    ) -> Task<Result<Vec<CodeAction>>>;
22029
22030    fn apply_code_action(
22031        &self,
22032        buffer_handle: Entity<Buffer>,
22033        action: CodeAction,
22034        excerpt_id: ExcerptId,
22035        push_to_history: bool,
22036        window: &mut Window,
22037        cx: &mut App,
22038    ) -> Task<Result<ProjectTransaction>>;
22039}
22040
22041impl CodeActionProvider for Entity<Project> {
22042    fn id(&self) -> Arc<str> {
22043        "project".into()
22044    }
22045
22046    fn code_actions(
22047        &self,
22048        buffer: &Entity<Buffer>,
22049        range: Range<text::Anchor>,
22050        _window: &mut Window,
22051        cx: &mut App,
22052    ) -> Task<Result<Vec<CodeAction>>> {
22053        self.update(cx, |project, cx| {
22054            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22055            let code_actions = project.code_actions(buffer, range, None, cx);
22056            cx.background_spawn(async move {
22057                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22058                Ok(code_lens_actions
22059                    .context("code lens fetch")?
22060                    .into_iter()
22061                    .chain(code_actions.context("code action fetch")?)
22062                    .collect())
22063            })
22064        })
22065    }
22066
22067    fn apply_code_action(
22068        &self,
22069        buffer_handle: Entity<Buffer>,
22070        action: CodeAction,
22071        _excerpt_id: ExcerptId,
22072        push_to_history: bool,
22073        _window: &mut Window,
22074        cx: &mut App,
22075    ) -> Task<Result<ProjectTransaction>> {
22076        self.update(cx, |project, cx| {
22077            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22078        })
22079    }
22080}
22081
22082fn snippet_completions(
22083    project: &Project,
22084    buffer: &Entity<Buffer>,
22085    buffer_position: text::Anchor,
22086    cx: &mut App,
22087) -> Task<Result<CompletionResponse>> {
22088    let languages = buffer.read(cx).languages_at(buffer_position);
22089    let snippet_store = project.snippets().read(cx);
22090
22091    let scopes: Vec<_> = languages
22092        .iter()
22093        .filter_map(|language| {
22094            let language_name = language.lsp_id();
22095            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22096
22097            if snippets.is_empty() {
22098                None
22099            } else {
22100                Some((language.default_scope(), snippets))
22101            }
22102        })
22103        .collect();
22104
22105    if scopes.is_empty() {
22106        return Task::ready(Ok(CompletionResponse {
22107            completions: vec![],
22108            is_incomplete: false,
22109        }));
22110    }
22111
22112    let snapshot = buffer.read(cx).text_snapshot();
22113    let chars: String = snapshot
22114        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22115        .collect();
22116    let executor = cx.background_executor().clone();
22117
22118    cx.background_spawn(async move {
22119        let mut is_incomplete = false;
22120        let mut completions: Vec<Completion> = Vec::new();
22121        for (scope, snippets) in scopes.into_iter() {
22122            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22123            let mut last_word = chars
22124                .chars()
22125                .take_while(|c| classifier.is_word(*c))
22126                .collect::<String>();
22127            last_word = last_word.chars().rev().collect();
22128
22129            if last_word.is_empty() {
22130                return Ok(CompletionResponse {
22131                    completions: vec![],
22132                    is_incomplete: true,
22133                });
22134            }
22135
22136            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22137            let to_lsp = |point: &text::Anchor| {
22138                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22139                point_to_lsp(end)
22140            };
22141            let lsp_end = to_lsp(&buffer_position);
22142
22143            let candidates = snippets
22144                .iter()
22145                .enumerate()
22146                .flat_map(|(ix, snippet)| {
22147                    snippet
22148                        .prefix
22149                        .iter()
22150                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22151                })
22152                .collect::<Vec<StringMatchCandidate>>();
22153
22154            const MAX_RESULTS: usize = 100;
22155            let mut matches = fuzzy::match_strings(
22156                &candidates,
22157                &last_word,
22158                last_word.chars().any(|c| c.is_uppercase()),
22159                true,
22160                MAX_RESULTS,
22161                &Default::default(),
22162                executor.clone(),
22163            )
22164            .await;
22165
22166            if matches.len() >= MAX_RESULTS {
22167                is_incomplete = true;
22168            }
22169
22170            // Remove all candidates where the query's start does not match the start of any word in the candidate
22171            if let Some(query_start) = last_word.chars().next() {
22172                matches.retain(|string_match| {
22173                    split_words(&string_match.string).any(|word| {
22174                        // Check that the first codepoint of the word as lowercase matches the first
22175                        // codepoint of the query as lowercase
22176                        word.chars()
22177                            .flat_map(|codepoint| codepoint.to_lowercase())
22178                            .zip(query_start.to_lowercase())
22179                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22180                    })
22181                });
22182            }
22183
22184            let matched_strings = matches
22185                .into_iter()
22186                .map(|m| m.string)
22187                .collect::<HashSet<_>>();
22188
22189            completions.extend(snippets.iter().filter_map(|snippet| {
22190                let matching_prefix = snippet
22191                    .prefix
22192                    .iter()
22193                    .find(|prefix| matched_strings.contains(*prefix))?;
22194                let start = as_offset - last_word.len();
22195                let start = snapshot.anchor_before(start);
22196                let range = start..buffer_position;
22197                let lsp_start = to_lsp(&start);
22198                let lsp_range = lsp::Range {
22199                    start: lsp_start,
22200                    end: lsp_end,
22201                };
22202                Some(Completion {
22203                    replace_range: range,
22204                    new_text: snippet.body.clone(),
22205                    source: CompletionSource::Lsp {
22206                        insert_range: None,
22207                        server_id: LanguageServerId(usize::MAX),
22208                        resolved: true,
22209                        lsp_completion: Box::new(lsp::CompletionItem {
22210                            label: snippet.prefix.first().unwrap().clone(),
22211                            kind: Some(CompletionItemKind::SNIPPET),
22212                            label_details: snippet.description.as_ref().map(|description| {
22213                                lsp::CompletionItemLabelDetails {
22214                                    detail: Some(description.clone()),
22215                                    description: None,
22216                                }
22217                            }),
22218                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22219                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22220                                lsp::InsertReplaceEdit {
22221                                    new_text: snippet.body.clone(),
22222                                    insert: lsp_range,
22223                                    replace: lsp_range,
22224                                },
22225                            )),
22226                            filter_text: Some(snippet.body.clone()),
22227                            sort_text: Some(char::MAX.to_string()),
22228                            ..lsp::CompletionItem::default()
22229                        }),
22230                        lsp_defaults: None,
22231                    },
22232                    label: CodeLabel {
22233                        text: matching_prefix.clone(),
22234                        runs: Vec::new(),
22235                        filter_range: 0..matching_prefix.len(),
22236                    },
22237                    icon_path: None,
22238                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22239                        single_line: snippet.name.clone().into(),
22240                        plain_text: snippet
22241                            .description
22242                            .clone()
22243                            .map(|description| description.into()),
22244                    }),
22245                    insert_text_mode: None,
22246                    confirm: None,
22247                })
22248            }))
22249        }
22250
22251        Ok(CompletionResponse {
22252            completions,
22253            is_incomplete,
22254        })
22255    })
22256}
22257
22258impl CompletionProvider for Entity<Project> {
22259    fn completions(
22260        &self,
22261        _excerpt_id: ExcerptId,
22262        buffer: &Entity<Buffer>,
22263        buffer_position: text::Anchor,
22264        options: CompletionContext,
22265        _window: &mut Window,
22266        cx: &mut Context<Editor>,
22267    ) -> Task<Result<Vec<CompletionResponse>>> {
22268        self.update(cx, |project, cx| {
22269            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22270            let project_completions = project.completions(buffer, buffer_position, options, cx);
22271            cx.background_spawn(async move {
22272                let mut responses = project_completions.await?;
22273                let snippets = snippets.await?;
22274                if !snippets.completions.is_empty() {
22275                    responses.push(snippets);
22276                }
22277                Ok(responses)
22278            })
22279        })
22280    }
22281
22282    fn resolve_completions(
22283        &self,
22284        buffer: Entity<Buffer>,
22285        completion_indices: Vec<usize>,
22286        completions: Rc<RefCell<Box<[Completion]>>>,
22287        cx: &mut Context<Editor>,
22288    ) -> Task<Result<bool>> {
22289        self.update(cx, |project, cx| {
22290            project.lsp_store().update(cx, |lsp_store, cx| {
22291                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22292            })
22293        })
22294    }
22295
22296    fn apply_additional_edits_for_completion(
22297        &self,
22298        buffer: Entity<Buffer>,
22299        completions: Rc<RefCell<Box<[Completion]>>>,
22300        completion_index: usize,
22301        push_to_history: bool,
22302        cx: &mut Context<Editor>,
22303    ) -> Task<Result<Option<language::Transaction>>> {
22304        self.update(cx, |project, cx| {
22305            project.lsp_store().update(cx, |lsp_store, cx| {
22306                lsp_store.apply_additional_edits_for_completion(
22307                    buffer,
22308                    completions,
22309                    completion_index,
22310                    push_to_history,
22311                    cx,
22312                )
22313            })
22314        })
22315    }
22316
22317    fn is_completion_trigger(
22318        &self,
22319        buffer: &Entity<Buffer>,
22320        position: language::Anchor,
22321        text: &str,
22322        trigger_in_words: bool,
22323        menu_is_open: bool,
22324        cx: &mut Context<Editor>,
22325    ) -> bool {
22326        let mut chars = text.chars();
22327        let char = if let Some(char) = chars.next() {
22328            char
22329        } else {
22330            return false;
22331        };
22332        if chars.next().is_some() {
22333            return false;
22334        }
22335
22336        let buffer = buffer.read(cx);
22337        let snapshot = buffer.snapshot();
22338        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22339            return false;
22340        }
22341        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22342        if trigger_in_words && classifier.is_word(char) {
22343            return true;
22344        }
22345
22346        buffer.completion_triggers().contains(text)
22347    }
22348}
22349
22350impl SemanticsProvider for Entity<Project> {
22351    fn hover(
22352        &self,
22353        buffer: &Entity<Buffer>,
22354        position: text::Anchor,
22355        cx: &mut App,
22356    ) -> Option<Task<Vec<project::Hover>>> {
22357        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22358    }
22359
22360    fn document_highlights(
22361        &self,
22362        buffer: &Entity<Buffer>,
22363        position: text::Anchor,
22364        cx: &mut App,
22365    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22366        Some(self.update(cx, |project, cx| {
22367            project.document_highlights(buffer, position, cx)
22368        }))
22369    }
22370
22371    fn definitions(
22372        &self,
22373        buffer: &Entity<Buffer>,
22374        position: text::Anchor,
22375        kind: GotoDefinitionKind,
22376        cx: &mut App,
22377    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22378        Some(self.update(cx, |project, cx| match kind {
22379            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22380            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22381            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22382            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22383        }))
22384    }
22385
22386    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22387        self.update(cx, |project, cx| {
22388            if project
22389                .active_debug_session(cx)
22390                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22391            {
22392                return true;
22393            }
22394
22395            buffer.update(cx, |buffer, cx| {
22396                project.any_language_server_supports_inlay_hints(buffer, cx)
22397            })
22398        })
22399    }
22400
22401    fn inline_values(
22402        &self,
22403        buffer_handle: Entity<Buffer>,
22404        range: Range<text::Anchor>,
22405        cx: &mut App,
22406    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22407        self.update(cx, |project, cx| {
22408            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22409
22410            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22411        })
22412    }
22413
22414    fn inlay_hints(
22415        &self,
22416        buffer_handle: Entity<Buffer>,
22417        range: Range<text::Anchor>,
22418        cx: &mut App,
22419    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22420        Some(self.update(cx, |project, cx| {
22421            project.inlay_hints(buffer_handle, range, cx)
22422        }))
22423    }
22424
22425    fn resolve_inlay_hint(
22426        &self,
22427        hint: InlayHint,
22428        buffer_handle: Entity<Buffer>,
22429        server_id: LanguageServerId,
22430        cx: &mut App,
22431    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22432        Some(self.update(cx, |project, cx| {
22433            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22434        }))
22435    }
22436
22437    fn range_for_rename(
22438        &self,
22439        buffer: &Entity<Buffer>,
22440        position: text::Anchor,
22441        cx: &mut App,
22442    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22443        Some(self.update(cx, |project, cx| {
22444            let buffer = buffer.clone();
22445            let task = project.prepare_rename(buffer.clone(), position, cx);
22446            cx.spawn(async move |_, cx| {
22447                Ok(match task.await? {
22448                    PrepareRenameResponse::Success(range) => Some(range),
22449                    PrepareRenameResponse::InvalidPosition => None,
22450                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22451                        // Fallback on using TreeSitter info to determine identifier range
22452                        buffer.read_with(cx, |buffer, _| {
22453                            let snapshot = buffer.snapshot();
22454                            let (range, kind) = snapshot.surrounding_word(position, false);
22455                            if kind != Some(CharKind::Word) {
22456                                return None;
22457                            }
22458                            Some(
22459                                snapshot.anchor_before(range.start)
22460                                    ..snapshot.anchor_after(range.end),
22461                            )
22462                        })?
22463                    }
22464                })
22465            })
22466        }))
22467    }
22468
22469    fn perform_rename(
22470        &self,
22471        buffer: &Entity<Buffer>,
22472        position: text::Anchor,
22473        new_name: String,
22474        cx: &mut App,
22475    ) -> Option<Task<Result<ProjectTransaction>>> {
22476        Some(self.update(cx, |project, cx| {
22477            project.perform_rename(buffer.clone(), position, new_name, cx)
22478        }))
22479    }
22480}
22481
22482fn inlay_hint_settings(
22483    location: Anchor,
22484    snapshot: &MultiBufferSnapshot,
22485    cx: &mut Context<Editor>,
22486) -> InlayHintSettings {
22487    let file = snapshot.file_at(location);
22488    let language = snapshot.language_at(location).map(|l| l.name());
22489    language_settings(language, file, cx).inlay_hints
22490}
22491
22492fn consume_contiguous_rows(
22493    contiguous_row_selections: &mut Vec<Selection<Point>>,
22494    selection: &Selection<Point>,
22495    display_map: &DisplaySnapshot,
22496    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22497) -> (MultiBufferRow, MultiBufferRow) {
22498    contiguous_row_selections.push(selection.clone());
22499    let start_row = starting_row(selection, display_map);
22500    let mut end_row = ending_row(selection, display_map);
22501
22502    while let Some(next_selection) = selections.peek() {
22503        if next_selection.start.row <= end_row.0 {
22504            end_row = ending_row(next_selection, display_map);
22505            contiguous_row_selections.push(selections.next().unwrap().clone());
22506        } else {
22507            break;
22508        }
22509    }
22510    (start_row, end_row)
22511}
22512
22513fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22514    if selection.start.column > 0 {
22515        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22516    } else {
22517        MultiBufferRow(selection.start.row)
22518    }
22519}
22520
22521fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22522    if next_selection.end.column > 0 || next_selection.is_empty() {
22523        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22524    } else {
22525        MultiBufferRow(next_selection.end.row)
22526    }
22527}
22528
22529impl EditorSnapshot {
22530    pub fn remote_selections_in_range<'a>(
22531        &'a self,
22532        range: &'a Range<Anchor>,
22533        collaboration_hub: &dyn CollaborationHub,
22534        cx: &'a App,
22535    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22536        let participant_names = collaboration_hub.user_names(cx);
22537        let participant_indices = collaboration_hub.user_participant_indices(cx);
22538        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22539        let collaborators_by_replica_id = collaborators_by_peer_id
22540            .values()
22541            .map(|collaborator| (collaborator.replica_id, collaborator))
22542            .collect::<HashMap<_, _>>();
22543        self.buffer_snapshot
22544            .selections_in_range(range, false)
22545            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22546                if replica_id == AGENT_REPLICA_ID {
22547                    Some(RemoteSelection {
22548                        replica_id,
22549                        selection,
22550                        cursor_shape,
22551                        line_mode,
22552                        collaborator_id: CollaboratorId::Agent,
22553                        user_name: Some("Agent".into()),
22554                        color: cx.theme().players().agent(),
22555                    })
22556                } else {
22557                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22558                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22559                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22560                    Some(RemoteSelection {
22561                        replica_id,
22562                        selection,
22563                        cursor_shape,
22564                        line_mode,
22565                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22566                        user_name,
22567                        color: if let Some(index) = participant_index {
22568                            cx.theme().players().color_for_participant(index.0)
22569                        } else {
22570                            cx.theme().players().absent()
22571                        },
22572                    })
22573                }
22574            })
22575    }
22576
22577    pub fn hunks_for_ranges(
22578        &self,
22579        ranges: impl IntoIterator<Item = Range<Point>>,
22580    ) -> Vec<MultiBufferDiffHunk> {
22581        let mut hunks = Vec::new();
22582        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22583            HashMap::default();
22584        for query_range in ranges {
22585            let query_rows =
22586                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22587            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22588                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22589            ) {
22590                // Include deleted hunks that are adjacent to the query range, because
22591                // otherwise they would be missed.
22592                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22593                if hunk.status().is_deleted() {
22594                    intersects_range |= hunk.row_range.start == query_rows.end;
22595                    intersects_range |= hunk.row_range.end == query_rows.start;
22596                }
22597                if intersects_range {
22598                    if !processed_buffer_rows
22599                        .entry(hunk.buffer_id)
22600                        .or_default()
22601                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22602                    {
22603                        continue;
22604                    }
22605                    hunks.push(hunk);
22606                }
22607            }
22608        }
22609
22610        hunks
22611    }
22612
22613    fn display_diff_hunks_for_rows<'a>(
22614        &'a self,
22615        display_rows: Range<DisplayRow>,
22616        folded_buffers: &'a HashSet<BufferId>,
22617    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22618        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22619        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22620
22621        self.buffer_snapshot
22622            .diff_hunks_in_range(buffer_start..buffer_end)
22623            .filter_map(|hunk| {
22624                if folded_buffers.contains(&hunk.buffer_id) {
22625                    return None;
22626                }
22627
22628                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22629                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22630
22631                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22632                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22633
22634                let display_hunk = if hunk_display_start.column() != 0 {
22635                    DisplayDiffHunk::Folded {
22636                        display_row: hunk_display_start.row(),
22637                    }
22638                } else {
22639                    let mut end_row = hunk_display_end.row();
22640                    if hunk_display_end.column() > 0 {
22641                        end_row.0 += 1;
22642                    }
22643                    let is_created_file = hunk.is_created_file();
22644                    DisplayDiffHunk::Unfolded {
22645                        status: hunk.status(),
22646                        diff_base_byte_range: hunk.diff_base_byte_range,
22647                        display_row_range: hunk_display_start.row()..end_row,
22648                        multi_buffer_range: Anchor::range_in_buffer(
22649                            hunk.excerpt_id,
22650                            hunk.buffer_id,
22651                            hunk.buffer_range,
22652                        ),
22653                        is_created_file,
22654                    }
22655                };
22656
22657                Some(display_hunk)
22658            })
22659    }
22660
22661    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22662        self.display_snapshot.buffer_snapshot.language_at(position)
22663    }
22664
22665    pub fn is_focused(&self) -> bool {
22666        self.is_focused
22667    }
22668
22669    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22670        self.placeholder_text.as_ref()
22671    }
22672
22673    pub fn scroll_position(&self) -> gpui::Point<f32> {
22674        self.scroll_anchor.scroll_position(&self.display_snapshot)
22675    }
22676
22677    fn gutter_dimensions(
22678        &self,
22679        font_id: FontId,
22680        font_size: Pixels,
22681        max_line_number_width: Pixels,
22682        cx: &App,
22683    ) -> Option<GutterDimensions> {
22684        if !self.show_gutter {
22685            return None;
22686        }
22687
22688        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22689        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22690
22691        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22692            matches!(
22693                ProjectSettings::get_global(cx).git.git_gutter,
22694                Some(GitGutterSetting::TrackedFiles)
22695            )
22696        });
22697        let gutter_settings = EditorSettings::get_global(cx).gutter;
22698        let show_line_numbers = self
22699            .show_line_numbers
22700            .unwrap_or(gutter_settings.line_numbers);
22701        let line_gutter_width = if show_line_numbers {
22702            // Avoid flicker-like gutter resizes when the line number gains another digit by
22703            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22704            let min_width_for_number_on_gutter =
22705                ch_advance * gutter_settings.min_line_number_digits as f32;
22706            max_line_number_width.max(min_width_for_number_on_gutter)
22707        } else {
22708            0.0.into()
22709        };
22710
22711        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22712        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22713
22714        let git_blame_entries_width =
22715            self.git_blame_gutter_max_author_length
22716                .map(|max_author_length| {
22717                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22718                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22719
22720                    /// The number of characters to dedicate to gaps and margins.
22721                    const SPACING_WIDTH: usize = 4;
22722
22723                    let max_char_count = max_author_length.min(renderer.max_author_length())
22724                        + ::git::SHORT_SHA_LENGTH
22725                        + MAX_RELATIVE_TIMESTAMP.len()
22726                        + SPACING_WIDTH;
22727
22728                    ch_advance * max_char_count
22729                });
22730
22731        let is_singleton = self.buffer_snapshot.is_singleton();
22732
22733        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22734        left_padding += if !is_singleton {
22735            ch_width * 4.0
22736        } else if show_runnables || show_breakpoints {
22737            ch_width * 3.0
22738        } else if show_git_gutter && show_line_numbers {
22739            ch_width * 2.0
22740        } else if show_git_gutter || show_line_numbers {
22741            ch_width
22742        } else {
22743            px(0.)
22744        };
22745
22746        let shows_folds = is_singleton && gutter_settings.folds;
22747
22748        let right_padding = if shows_folds && show_line_numbers {
22749            ch_width * 4.0
22750        } else if shows_folds || (!is_singleton && show_line_numbers) {
22751            ch_width * 3.0
22752        } else if show_line_numbers {
22753            ch_width
22754        } else {
22755            px(0.)
22756        };
22757
22758        Some(GutterDimensions {
22759            left_padding,
22760            right_padding,
22761            width: line_gutter_width + left_padding + right_padding,
22762            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22763            git_blame_entries_width,
22764        })
22765    }
22766
22767    pub fn render_crease_toggle(
22768        &self,
22769        buffer_row: MultiBufferRow,
22770        row_contains_cursor: bool,
22771        editor: Entity<Editor>,
22772        window: &mut Window,
22773        cx: &mut App,
22774    ) -> Option<AnyElement> {
22775        let folded = self.is_line_folded(buffer_row);
22776        let mut is_foldable = false;
22777
22778        if let Some(crease) = self
22779            .crease_snapshot
22780            .query_row(buffer_row, &self.buffer_snapshot)
22781        {
22782            is_foldable = true;
22783            match crease {
22784                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22785                    if let Some(render_toggle) = render_toggle {
22786                        let toggle_callback =
22787                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22788                                if folded {
22789                                    editor.update(cx, |editor, cx| {
22790                                        editor.fold_at(buffer_row, window, cx)
22791                                    });
22792                                } else {
22793                                    editor.update(cx, |editor, cx| {
22794                                        editor.unfold_at(buffer_row, window, cx)
22795                                    });
22796                                }
22797                            });
22798                        return Some((render_toggle)(
22799                            buffer_row,
22800                            folded,
22801                            toggle_callback,
22802                            window,
22803                            cx,
22804                        ));
22805                    }
22806                }
22807            }
22808        }
22809
22810        is_foldable |= self.starts_indent(buffer_row);
22811
22812        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22813            Some(
22814                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22815                    .toggle_state(folded)
22816                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22817                        if folded {
22818                            this.unfold_at(buffer_row, window, cx);
22819                        } else {
22820                            this.fold_at(buffer_row, window, cx);
22821                        }
22822                    }))
22823                    .into_any_element(),
22824            )
22825        } else {
22826            None
22827        }
22828    }
22829
22830    pub fn render_crease_trailer(
22831        &self,
22832        buffer_row: MultiBufferRow,
22833        window: &mut Window,
22834        cx: &mut App,
22835    ) -> Option<AnyElement> {
22836        let folded = self.is_line_folded(buffer_row);
22837        if let Crease::Inline { render_trailer, .. } = self
22838            .crease_snapshot
22839            .query_row(buffer_row, &self.buffer_snapshot)?
22840        {
22841            let render_trailer = render_trailer.as_ref()?;
22842            Some(render_trailer(buffer_row, folded, window, cx))
22843        } else {
22844            None
22845        }
22846    }
22847}
22848
22849impl Deref for EditorSnapshot {
22850    type Target = DisplaySnapshot;
22851
22852    fn deref(&self) -> &Self::Target {
22853        &self.display_snapshot
22854    }
22855}
22856
22857#[derive(Clone, Debug, PartialEq, Eq)]
22858pub enum EditorEvent {
22859    InputIgnored {
22860        text: Arc<str>,
22861    },
22862    InputHandled {
22863        utf16_range_to_replace: Option<Range<isize>>,
22864        text: Arc<str>,
22865    },
22866    ExcerptsAdded {
22867        buffer: Entity<Buffer>,
22868        predecessor: ExcerptId,
22869        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22870    },
22871    ExcerptsRemoved {
22872        ids: Vec<ExcerptId>,
22873        removed_buffer_ids: Vec<BufferId>,
22874    },
22875    BufferFoldToggled {
22876        ids: Vec<ExcerptId>,
22877        folded: bool,
22878    },
22879    ExcerptsEdited {
22880        ids: Vec<ExcerptId>,
22881    },
22882    ExcerptsExpanded {
22883        ids: Vec<ExcerptId>,
22884    },
22885    BufferEdited,
22886    Edited {
22887        transaction_id: clock::Lamport,
22888    },
22889    Reparsed(BufferId),
22890    Focused,
22891    FocusedIn,
22892    Blurred,
22893    DirtyChanged,
22894    Saved,
22895    TitleChanged,
22896    DiffBaseChanged,
22897    SelectionsChanged {
22898        local: bool,
22899    },
22900    ScrollPositionChanged {
22901        local: bool,
22902        autoscroll: bool,
22903    },
22904    Closed,
22905    TransactionUndone {
22906        transaction_id: clock::Lamport,
22907    },
22908    TransactionBegun {
22909        transaction_id: clock::Lamport,
22910    },
22911    Reloaded,
22912    CursorShapeChanged,
22913    BreadcrumbsChanged,
22914    PushedToNavHistory {
22915        anchor: Anchor,
22916        is_deactivate: bool,
22917    },
22918}
22919
22920impl EventEmitter<EditorEvent> for Editor {}
22921
22922impl Focusable for Editor {
22923    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22924        self.focus_handle.clone()
22925    }
22926}
22927
22928impl Render for Editor {
22929    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22930        let settings = ThemeSettings::get_global(cx);
22931
22932        let mut text_style = match self.mode {
22933            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22934                color: cx.theme().colors().editor_foreground,
22935                font_family: settings.ui_font.family.clone(),
22936                font_features: settings.ui_font.features.clone(),
22937                font_fallbacks: settings.ui_font.fallbacks.clone(),
22938                font_size: rems(0.875).into(),
22939                font_weight: settings.ui_font.weight,
22940                line_height: relative(settings.buffer_line_height.value()),
22941                ..Default::default()
22942            },
22943            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22944                color: cx.theme().colors().editor_foreground,
22945                font_family: settings.buffer_font.family.clone(),
22946                font_features: settings.buffer_font.features.clone(),
22947                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22948                font_size: settings.buffer_font_size(cx).into(),
22949                font_weight: settings.buffer_font.weight,
22950                line_height: relative(settings.buffer_line_height.value()),
22951                ..Default::default()
22952            },
22953        };
22954        if let Some(text_style_refinement) = &self.text_style_refinement {
22955            text_style.refine(text_style_refinement)
22956        }
22957
22958        let background = match self.mode {
22959            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22960            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22961            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22962            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22963        };
22964
22965        EditorElement::new(
22966            &cx.entity(),
22967            EditorStyle {
22968                background,
22969                border: cx.theme().colors().border,
22970                local_player: cx.theme().players().local(),
22971                text: text_style,
22972                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22973                syntax: cx.theme().syntax().clone(),
22974                status: cx.theme().status().clone(),
22975                inlay_hints_style: make_inlay_hints_style(cx),
22976                edit_prediction_styles: make_suggestion_styles(cx),
22977                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22978                show_underlines: self.diagnostics_enabled(),
22979            },
22980        )
22981    }
22982}
22983
22984impl EntityInputHandler for Editor {
22985    fn text_for_range(
22986        &mut self,
22987        range_utf16: Range<usize>,
22988        adjusted_range: &mut Option<Range<usize>>,
22989        _: &mut Window,
22990        cx: &mut Context<Self>,
22991    ) -> Option<String> {
22992        let snapshot = self.buffer.read(cx).read(cx);
22993        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22994        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22995        if (start.0..end.0) != range_utf16 {
22996            adjusted_range.replace(start.0..end.0);
22997        }
22998        Some(snapshot.text_for_range(start..end).collect())
22999    }
23000
23001    fn selected_text_range(
23002        &mut self,
23003        ignore_disabled_input: bool,
23004        _: &mut Window,
23005        cx: &mut Context<Self>,
23006    ) -> Option<UTF16Selection> {
23007        // Prevent the IME menu from appearing when holding down an alphabetic key
23008        // while input is disabled.
23009        if !ignore_disabled_input && !self.input_enabled {
23010            return None;
23011        }
23012
23013        let selection = self.selections.newest::<OffsetUtf16>(cx);
23014        let range = selection.range();
23015
23016        Some(UTF16Selection {
23017            range: range.start.0..range.end.0,
23018            reversed: selection.reversed,
23019        })
23020    }
23021
23022    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23023        let snapshot = self.buffer.read(cx).read(cx);
23024        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23025        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23026    }
23027
23028    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23029        self.clear_highlights::<InputComposition>(cx);
23030        self.ime_transaction.take();
23031    }
23032
23033    fn replace_text_in_range(
23034        &mut self,
23035        range_utf16: Option<Range<usize>>,
23036        text: &str,
23037        window: &mut Window,
23038        cx: &mut Context<Self>,
23039    ) {
23040        if !self.input_enabled {
23041            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23042            return;
23043        }
23044
23045        self.transact(window, cx, |this, window, cx| {
23046            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23047                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23048                Some(this.selection_replacement_ranges(range_utf16, cx))
23049            } else {
23050                this.marked_text_ranges(cx)
23051            };
23052
23053            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23054                let newest_selection_id = this.selections.newest_anchor().id;
23055                this.selections
23056                    .all::<OffsetUtf16>(cx)
23057                    .iter()
23058                    .zip(ranges_to_replace.iter())
23059                    .find_map(|(selection, range)| {
23060                        if selection.id == newest_selection_id {
23061                            Some(
23062                                (range.start.0 as isize - selection.head().0 as isize)
23063                                    ..(range.end.0 as isize - selection.head().0 as isize),
23064                            )
23065                        } else {
23066                            None
23067                        }
23068                    })
23069            });
23070
23071            cx.emit(EditorEvent::InputHandled {
23072                utf16_range_to_replace: range_to_replace,
23073                text: text.into(),
23074            });
23075
23076            if let Some(new_selected_ranges) = new_selected_ranges {
23077                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23078                    selections.select_ranges(new_selected_ranges)
23079                });
23080                this.backspace(&Default::default(), window, cx);
23081            }
23082
23083            this.handle_input(text, window, cx);
23084        });
23085
23086        if let Some(transaction) = self.ime_transaction {
23087            self.buffer.update(cx, |buffer, cx| {
23088                buffer.group_until_transaction(transaction, cx);
23089            });
23090        }
23091
23092        self.unmark_text(window, cx);
23093    }
23094
23095    fn replace_and_mark_text_in_range(
23096        &mut self,
23097        range_utf16: Option<Range<usize>>,
23098        text: &str,
23099        new_selected_range_utf16: Option<Range<usize>>,
23100        window: &mut Window,
23101        cx: &mut Context<Self>,
23102    ) {
23103        if !self.input_enabled {
23104            return;
23105        }
23106
23107        let transaction = self.transact(window, cx, |this, window, cx| {
23108            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23109                let snapshot = this.buffer.read(cx).read(cx);
23110                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23111                    for marked_range in &mut marked_ranges {
23112                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23113                        marked_range.start.0 += relative_range_utf16.start;
23114                        marked_range.start =
23115                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23116                        marked_range.end =
23117                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23118                    }
23119                }
23120                Some(marked_ranges)
23121            } else if let Some(range_utf16) = range_utf16 {
23122                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23123                Some(this.selection_replacement_ranges(range_utf16, cx))
23124            } else {
23125                None
23126            };
23127
23128            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23129                let newest_selection_id = this.selections.newest_anchor().id;
23130                this.selections
23131                    .all::<OffsetUtf16>(cx)
23132                    .iter()
23133                    .zip(ranges_to_replace.iter())
23134                    .find_map(|(selection, range)| {
23135                        if selection.id == newest_selection_id {
23136                            Some(
23137                                (range.start.0 as isize - selection.head().0 as isize)
23138                                    ..(range.end.0 as isize - selection.head().0 as isize),
23139                            )
23140                        } else {
23141                            None
23142                        }
23143                    })
23144            });
23145
23146            cx.emit(EditorEvent::InputHandled {
23147                utf16_range_to_replace: range_to_replace,
23148                text: text.into(),
23149            });
23150
23151            if let Some(ranges) = ranges_to_replace {
23152                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23153                    s.select_ranges(ranges)
23154                });
23155            }
23156
23157            let marked_ranges = {
23158                let snapshot = this.buffer.read(cx).read(cx);
23159                this.selections
23160                    .disjoint_anchors()
23161                    .iter()
23162                    .map(|selection| {
23163                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23164                    })
23165                    .collect::<Vec<_>>()
23166            };
23167
23168            if text.is_empty() {
23169                this.unmark_text(window, cx);
23170            } else {
23171                this.highlight_text::<InputComposition>(
23172                    marked_ranges.clone(),
23173                    HighlightStyle {
23174                        underline: Some(UnderlineStyle {
23175                            thickness: px(1.),
23176                            color: None,
23177                            wavy: false,
23178                        }),
23179                        ..Default::default()
23180                    },
23181                    cx,
23182                );
23183            }
23184
23185            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23186            let use_autoclose = this.use_autoclose;
23187            let use_auto_surround = this.use_auto_surround;
23188            this.set_use_autoclose(false);
23189            this.set_use_auto_surround(false);
23190            this.handle_input(text, window, cx);
23191            this.set_use_autoclose(use_autoclose);
23192            this.set_use_auto_surround(use_auto_surround);
23193
23194            if let Some(new_selected_range) = new_selected_range_utf16 {
23195                let snapshot = this.buffer.read(cx).read(cx);
23196                let new_selected_ranges = marked_ranges
23197                    .into_iter()
23198                    .map(|marked_range| {
23199                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23200                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23201                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23202                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23203                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23204                    })
23205                    .collect::<Vec<_>>();
23206
23207                drop(snapshot);
23208                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23209                    selections.select_ranges(new_selected_ranges)
23210                });
23211            }
23212        });
23213
23214        self.ime_transaction = self.ime_transaction.or(transaction);
23215        if let Some(transaction) = self.ime_transaction {
23216            self.buffer.update(cx, |buffer, cx| {
23217                buffer.group_until_transaction(transaction, cx);
23218            });
23219        }
23220
23221        if self.text_highlights::<InputComposition>(cx).is_none() {
23222            self.ime_transaction.take();
23223        }
23224    }
23225
23226    fn bounds_for_range(
23227        &mut self,
23228        range_utf16: Range<usize>,
23229        element_bounds: gpui::Bounds<Pixels>,
23230        window: &mut Window,
23231        cx: &mut Context<Self>,
23232    ) -> Option<gpui::Bounds<Pixels>> {
23233        let text_layout_details = self.text_layout_details(window);
23234        let CharacterDimensions {
23235            em_width,
23236            em_advance,
23237            line_height,
23238        } = self.character_dimensions(window);
23239
23240        let snapshot = self.snapshot(window, cx);
23241        let scroll_position = snapshot.scroll_position();
23242        let scroll_left = scroll_position.x * em_advance;
23243
23244        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23245        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23246            + self.gutter_dimensions.full_width();
23247        let y = line_height * (start.row().as_f32() - scroll_position.y);
23248
23249        Some(Bounds {
23250            origin: element_bounds.origin + point(x, y),
23251            size: size(em_width, line_height),
23252        })
23253    }
23254
23255    fn character_index_for_point(
23256        &mut self,
23257        point: gpui::Point<Pixels>,
23258        _window: &mut Window,
23259        _cx: &mut Context<Self>,
23260    ) -> Option<usize> {
23261        let position_map = self.last_position_map.as_ref()?;
23262        if !position_map.text_hitbox.contains(&point) {
23263            return None;
23264        }
23265        let display_point = position_map.point_for_position(point).previous_valid;
23266        let anchor = position_map
23267            .snapshot
23268            .display_point_to_anchor(display_point, Bias::Left);
23269        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23270        Some(utf16_offset.0)
23271    }
23272}
23273
23274trait SelectionExt {
23275    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23276    fn spanned_rows(
23277        &self,
23278        include_end_if_at_line_start: bool,
23279        map: &DisplaySnapshot,
23280    ) -> Range<MultiBufferRow>;
23281}
23282
23283impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23284    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23285        let start = self
23286            .start
23287            .to_point(&map.buffer_snapshot)
23288            .to_display_point(map);
23289        let end = self
23290            .end
23291            .to_point(&map.buffer_snapshot)
23292            .to_display_point(map);
23293        if self.reversed {
23294            end..start
23295        } else {
23296            start..end
23297        }
23298    }
23299
23300    fn spanned_rows(
23301        &self,
23302        include_end_if_at_line_start: bool,
23303        map: &DisplaySnapshot,
23304    ) -> Range<MultiBufferRow> {
23305        let start = self.start.to_point(&map.buffer_snapshot);
23306        let mut end = self.end.to_point(&map.buffer_snapshot);
23307        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23308            end.row -= 1;
23309        }
23310
23311        let buffer_start = map.prev_line_boundary(start).0;
23312        let buffer_end = map.next_line_boundary(end).0;
23313        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23314    }
23315}
23316
23317impl<T: InvalidationRegion> InvalidationStack<T> {
23318    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23319    where
23320        S: Clone + ToOffset,
23321    {
23322        while let Some(region) = self.last() {
23323            let all_selections_inside_invalidation_ranges =
23324                if selections.len() == region.ranges().len() {
23325                    selections
23326                        .iter()
23327                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23328                        .all(|(selection, invalidation_range)| {
23329                            let head = selection.head().to_offset(buffer);
23330                            invalidation_range.start <= head && invalidation_range.end >= head
23331                        })
23332                } else {
23333                    false
23334                };
23335
23336            if all_selections_inside_invalidation_ranges {
23337                break;
23338            } else {
23339                self.pop();
23340            }
23341        }
23342    }
23343}
23344
23345impl<T> Default for InvalidationStack<T> {
23346    fn default() -> Self {
23347        Self(Default::default())
23348    }
23349}
23350
23351impl<T> Deref for InvalidationStack<T> {
23352    type Target = Vec<T>;
23353
23354    fn deref(&self) -> &Self::Target {
23355        &self.0
23356    }
23357}
23358
23359impl<T> DerefMut for InvalidationStack<T> {
23360    fn deref_mut(&mut self) -> &mut Self::Target {
23361        &mut self.0
23362    }
23363}
23364
23365impl InvalidationRegion for SnippetState {
23366    fn ranges(&self) -> &[Range<Anchor>] {
23367        &self.ranges[self.active_index]
23368    }
23369}
23370
23371fn edit_prediction_edit_text(
23372    current_snapshot: &BufferSnapshot,
23373    edits: &[(Range<Anchor>, String)],
23374    edit_preview: &EditPreview,
23375    include_deletions: bool,
23376    cx: &App,
23377) -> HighlightedText {
23378    let edits = edits
23379        .iter()
23380        .map(|(anchor, text)| {
23381            (
23382                anchor.start.text_anchor..anchor.end.text_anchor,
23383                text.clone(),
23384            )
23385        })
23386        .collect::<Vec<_>>();
23387
23388    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23389}
23390
23391fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23392    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23393    // Just show the raw edit text with basic styling
23394    let mut text = String::new();
23395    let mut highlights = Vec::new();
23396
23397    let insertion_highlight_style = HighlightStyle {
23398        color: Some(cx.theme().colors().text),
23399        ..Default::default()
23400    };
23401
23402    for (_, edit_text) in edits {
23403        let start_offset = text.len();
23404        text.push_str(edit_text);
23405        let end_offset = text.len();
23406
23407        if start_offset < end_offset {
23408            highlights.push((start_offset..end_offset, insertion_highlight_style));
23409        }
23410    }
23411
23412    HighlightedText {
23413        text: text.into(),
23414        highlights,
23415    }
23416}
23417
23418pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23419    match severity {
23420        lsp::DiagnosticSeverity::ERROR => colors.error,
23421        lsp::DiagnosticSeverity::WARNING => colors.warning,
23422        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23423        lsp::DiagnosticSeverity::HINT => colors.info,
23424        _ => colors.ignored,
23425    }
23426}
23427
23428pub fn styled_runs_for_code_label<'a>(
23429    label: &'a CodeLabel,
23430    syntax_theme: &'a theme::SyntaxTheme,
23431) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23432    let fade_out = HighlightStyle {
23433        fade_out: Some(0.35),
23434        ..Default::default()
23435    };
23436
23437    let mut prev_end = label.filter_range.end;
23438    label
23439        .runs
23440        .iter()
23441        .enumerate()
23442        .flat_map(move |(ix, (range, highlight_id))| {
23443            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23444                style
23445            } else {
23446                return Default::default();
23447            };
23448            let mut muted_style = style;
23449            muted_style.highlight(fade_out);
23450
23451            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23452            if range.start >= label.filter_range.end {
23453                if range.start > prev_end {
23454                    runs.push((prev_end..range.start, fade_out));
23455                }
23456                runs.push((range.clone(), muted_style));
23457            } else if range.end <= label.filter_range.end {
23458                runs.push((range.clone(), style));
23459            } else {
23460                runs.push((range.start..label.filter_range.end, style));
23461                runs.push((label.filter_range.end..range.end, muted_style));
23462            }
23463            prev_end = cmp::max(prev_end, range.end);
23464
23465            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23466                runs.push((prev_end..label.text.len(), fade_out));
23467            }
23468
23469            runs
23470        })
23471}
23472
23473pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23474    let mut prev_index = 0;
23475    let mut prev_codepoint: Option<char> = None;
23476    text.char_indices()
23477        .chain([(text.len(), '\0')])
23478        .filter_map(move |(index, codepoint)| {
23479            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23480            let is_boundary = index == text.len()
23481                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23482                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23483            if is_boundary {
23484                let chunk = &text[prev_index..index];
23485                prev_index = index;
23486                Some(chunk)
23487            } else {
23488                None
23489            }
23490        })
23491}
23492
23493pub trait RangeToAnchorExt: Sized {
23494    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23495
23496    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23497        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23498        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23499    }
23500}
23501
23502impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23503    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23504        let start_offset = self.start.to_offset(snapshot);
23505        let end_offset = self.end.to_offset(snapshot);
23506        if start_offset == end_offset {
23507            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23508        } else {
23509            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23510        }
23511    }
23512}
23513
23514pub trait RowExt {
23515    fn as_f32(&self) -> f32;
23516
23517    fn next_row(&self) -> Self;
23518
23519    fn previous_row(&self) -> Self;
23520
23521    fn minus(&self, other: Self) -> u32;
23522}
23523
23524impl RowExt for DisplayRow {
23525    fn as_f32(&self) -> f32 {
23526        self.0 as f32
23527    }
23528
23529    fn next_row(&self) -> Self {
23530        Self(self.0 + 1)
23531    }
23532
23533    fn previous_row(&self) -> Self {
23534        Self(self.0.saturating_sub(1))
23535    }
23536
23537    fn minus(&self, other: Self) -> u32 {
23538        self.0 - other.0
23539    }
23540}
23541
23542impl RowExt for MultiBufferRow {
23543    fn as_f32(&self) -> f32 {
23544        self.0 as f32
23545    }
23546
23547    fn next_row(&self) -> Self {
23548        Self(self.0 + 1)
23549    }
23550
23551    fn previous_row(&self) -> Self {
23552        Self(self.0.saturating_sub(1))
23553    }
23554
23555    fn minus(&self, other: Self) -> u32 {
23556        self.0 - other.0
23557    }
23558}
23559
23560trait RowRangeExt {
23561    type Row;
23562
23563    fn len(&self) -> usize;
23564
23565    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23566}
23567
23568impl RowRangeExt for Range<MultiBufferRow> {
23569    type Row = MultiBufferRow;
23570
23571    fn len(&self) -> usize {
23572        (self.end.0 - self.start.0) as usize
23573    }
23574
23575    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23576        (self.start.0..self.end.0).map(MultiBufferRow)
23577    }
23578}
23579
23580impl RowRangeExt for Range<DisplayRow> {
23581    type Row = DisplayRow;
23582
23583    fn len(&self) -> usize {
23584        (self.end.0 - self.start.0) as usize
23585    }
23586
23587    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23588        (self.start.0..self.end.0).map(DisplayRow)
23589    }
23590}
23591
23592/// If select range has more than one line, we
23593/// just point the cursor to range.start.
23594fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23595    if range.start.row == range.end.row {
23596        range
23597    } else {
23598        range.start..range.start
23599    }
23600}
23601pub struct KillRing(ClipboardItem);
23602impl Global for KillRing {}
23603
23604const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23605
23606enum BreakpointPromptEditAction {
23607    Log,
23608    Condition,
23609    HitCondition,
23610}
23611
23612struct BreakpointPromptEditor {
23613    pub(crate) prompt: Entity<Editor>,
23614    editor: WeakEntity<Editor>,
23615    breakpoint_anchor: Anchor,
23616    breakpoint: Breakpoint,
23617    edit_action: BreakpointPromptEditAction,
23618    block_ids: HashSet<CustomBlockId>,
23619    editor_margins: Arc<Mutex<EditorMargins>>,
23620    _subscriptions: Vec<Subscription>,
23621}
23622
23623impl BreakpointPromptEditor {
23624    const MAX_LINES: u8 = 4;
23625
23626    fn new(
23627        editor: WeakEntity<Editor>,
23628        breakpoint_anchor: Anchor,
23629        breakpoint: Breakpoint,
23630        edit_action: BreakpointPromptEditAction,
23631        window: &mut Window,
23632        cx: &mut Context<Self>,
23633    ) -> Self {
23634        let base_text = match edit_action {
23635            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23636            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23637            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23638        }
23639        .map(|msg| msg.to_string())
23640        .unwrap_or_default();
23641
23642        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23643        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23644
23645        let prompt = cx.new(|cx| {
23646            let mut prompt = Editor::new(
23647                EditorMode::AutoHeight {
23648                    min_lines: 1,
23649                    max_lines: Some(Self::MAX_LINES as usize),
23650                },
23651                buffer,
23652                None,
23653                window,
23654                cx,
23655            );
23656            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23657            prompt.set_show_cursor_when_unfocused(false, cx);
23658            prompt.set_placeholder_text(
23659                match edit_action {
23660                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23661                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23662                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23663                },
23664                cx,
23665            );
23666
23667            prompt
23668        });
23669
23670        Self {
23671            prompt,
23672            editor,
23673            breakpoint_anchor,
23674            breakpoint,
23675            edit_action,
23676            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23677            block_ids: Default::default(),
23678            _subscriptions: vec![],
23679        }
23680    }
23681
23682    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23683        self.block_ids.extend(block_ids)
23684    }
23685
23686    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23687        if let Some(editor) = self.editor.upgrade() {
23688            let message = self
23689                .prompt
23690                .read(cx)
23691                .buffer
23692                .read(cx)
23693                .as_singleton()
23694                .expect("A multi buffer in breakpoint prompt isn't possible")
23695                .read(cx)
23696                .as_rope()
23697                .to_string();
23698
23699            editor.update(cx, |editor, cx| {
23700                editor.edit_breakpoint_at_anchor(
23701                    self.breakpoint_anchor,
23702                    self.breakpoint.clone(),
23703                    match self.edit_action {
23704                        BreakpointPromptEditAction::Log => {
23705                            BreakpointEditAction::EditLogMessage(message.into())
23706                        }
23707                        BreakpointPromptEditAction::Condition => {
23708                            BreakpointEditAction::EditCondition(message.into())
23709                        }
23710                        BreakpointPromptEditAction::HitCondition => {
23711                            BreakpointEditAction::EditHitCondition(message.into())
23712                        }
23713                    },
23714                    cx,
23715                );
23716
23717                editor.remove_blocks(self.block_ids.clone(), None, cx);
23718                cx.focus_self(window);
23719            });
23720        }
23721    }
23722
23723    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23724        self.editor
23725            .update(cx, |editor, cx| {
23726                editor.remove_blocks(self.block_ids.clone(), None, cx);
23727                window.focus(&editor.focus_handle);
23728            })
23729            .log_err();
23730    }
23731
23732    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23733        let settings = ThemeSettings::get_global(cx);
23734        let text_style = TextStyle {
23735            color: if self.prompt.read(cx).read_only(cx) {
23736                cx.theme().colors().text_disabled
23737            } else {
23738                cx.theme().colors().text
23739            },
23740            font_family: settings.buffer_font.family.clone(),
23741            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23742            font_size: settings.buffer_font_size(cx).into(),
23743            font_weight: settings.buffer_font.weight,
23744            line_height: relative(settings.buffer_line_height.value()),
23745            ..Default::default()
23746        };
23747        EditorElement::new(
23748            &self.prompt,
23749            EditorStyle {
23750                background: cx.theme().colors().editor_background,
23751                local_player: cx.theme().players().local(),
23752                text: text_style,
23753                ..Default::default()
23754            },
23755        )
23756    }
23757}
23758
23759impl Render for BreakpointPromptEditor {
23760    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23761        let editor_margins = *self.editor_margins.lock();
23762        let gutter_dimensions = editor_margins.gutter;
23763        h_flex()
23764            .key_context("Editor")
23765            .bg(cx.theme().colors().editor_background)
23766            .border_y_1()
23767            .border_color(cx.theme().status().info_border)
23768            .size_full()
23769            .py(window.line_height() / 2.5)
23770            .on_action(cx.listener(Self::confirm))
23771            .on_action(cx.listener(Self::cancel))
23772            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23773            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23774    }
23775}
23776
23777impl Focusable for BreakpointPromptEditor {
23778    fn focus_handle(&self, cx: &App) -> FocusHandle {
23779        self.prompt.focus_handle(cx)
23780    }
23781}
23782
23783fn all_edits_insertions_or_deletions(
23784    edits: &Vec<(Range<Anchor>, String)>,
23785    snapshot: &MultiBufferSnapshot,
23786) -> bool {
23787    let mut all_insertions = true;
23788    let mut all_deletions = true;
23789
23790    for (range, new_text) in edits.iter() {
23791        let range_is_empty = range.to_offset(snapshot).is_empty();
23792        let text_is_empty = new_text.is_empty();
23793
23794        if range_is_empty != text_is_empty {
23795            if range_is_empty {
23796                all_deletions = false;
23797            } else {
23798                all_insertions = false;
23799            }
23800        } else {
23801            return false;
23802        }
23803
23804        if !all_insertions && !all_deletions {
23805            return false;
23806        }
23807    }
23808    all_insertions || all_deletions
23809}
23810
23811struct MissingEditPredictionKeybindingTooltip;
23812
23813impl Render for MissingEditPredictionKeybindingTooltip {
23814    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23815        ui::tooltip_container(window, cx, |container, _, cx| {
23816            container
23817                .flex_shrink_0()
23818                .max_w_80()
23819                .min_h(rems_from_px(124.))
23820                .justify_between()
23821                .child(
23822                    v_flex()
23823                        .flex_1()
23824                        .text_ui_sm(cx)
23825                        .child(Label::new("Conflict with Accept Keybinding"))
23826                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23827                )
23828                .child(
23829                    h_flex()
23830                        .pb_1()
23831                        .gap_1()
23832                        .items_end()
23833                        .w_full()
23834                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23835                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23836                        }))
23837                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23838                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23839                        })),
23840                )
23841        })
23842    }
23843}
23844
23845#[derive(Debug, Clone, Copy, PartialEq)]
23846pub struct LineHighlight {
23847    pub background: Background,
23848    pub border: Option<gpui::Hsla>,
23849    pub include_gutter: bool,
23850    pub type_id: Option<TypeId>,
23851}
23852
23853struct LineManipulationResult {
23854    pub new_text: String,
23855    pub line_count_before: usize,
23856    pub line_count_after: usize,
23857}
23858
23859fn render_diff_hunk_controls(
23860    row: u32,
23861    status: &DiffHunkStatus,
23862    hunk_range: Range<Anchor>,
23863    is_created_file: bool,
23864    line_height: Pixels,
23865    editor: &Entity<Editor>,
23866    _window: &mut Window,
23867    cx: &mut App,
23868) -> AnyElement {
23869    h_flex()
23870        .h(line_height)
23871        .mr_1()
23872        .gap_1()
23873        .px_0p5()
23874        .pb_1()
23875        .border_x_1()
23876        .border_b_1()
23877        .border_color(cx.theme().colors().border_variant)
23878        .rounded_b_lg()
23879        .bg(cx.theme().colors().editor_background)
23880        .gap_1()
23881        .block_mouse_except_scroll()
23882        .shadow_md()
23883        .child(if status.has_secondary_hunk() {
23884            Button::new(("stage", row as u64), "Stage")
23885                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23886                .tooltip({
23887                    let focus_handle = editor.focus_handle(cx);
23888                    move |window, cx| {
23889                        Tooltip::for_action_in(
23890                            "Stage Hunk",
23891                            &::git::ToggleStaged,
23892                            &focus_handle,
23893                            window,
23894                            cx,
23895                        )
23896                    }
23897                })
23898                .on_click({
23899                    let editor = editor.clone();
23900                    move |_event, _window, cx| {
23901                        editor.update(cx, |editor, cx| {
23902                            editor.stage_or_unstage_diff_hunks(
23903                                true,
23904                                vec![hunk_range.start..hunk_range.start],
23905                                cx,
23906                            );
23907                        });
23908                    }
23909                })
23910        } else {
23911            Button::new(("unstage", row as u64), "Unstage")
23912                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23913                .tooltip({
23914                    let focus_handle = editor.focus_handle(cx);
23915                    move |window, cx| {
23916                        Tooltip::for_action_in(
23917                            "Unstage Hunk",
23918                            &::git::ToggleStaged,
23919                            &focus_handle,
23920                            window,
23921                            cx,
23922                        )
23923                    }
23924                })
23925                .on_click({
23926                    let editor = editor.clone();
23927                    move |_event, _window, cx| {
23928                        editor.update(cx, |editor, cx| {
23929                            editor.stage_or_unstage_diff_hunks(
23930                                false,
23931                                vec![hunk_range.start..hunk_range.start],
23932                                cx,
23933                            );
23934                        });
23935                    }
23936                })
23937        })
23938        .child(
23939            Button::new(("restore", row as u64), "Restore")
23940                .tooltip({
23941                    let focus_handle = editor.focus_handle(cx);
23942                    move |window, cx| {
23943                        Tooltip::for_action_in(
23944                            "Restore Hunk",
23945                            &::git::Restore,
23946                            &focus_handle,
23947                            window,
23948                            cx,
23949                        )
23950                    }
23951                })
23952                .on_click({
23953                    let editor = editor.clone();
23954                    move |_event, window, cx| {
23955                        editor.update(cx, |editor, cx| {
23956                            let snapshot = editor.snapshot(window, cx);
23957                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23958                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23959                        });
23960                    }
23961                })
23962                .disabled(is_created_file),
23963        )
23964        .when(
23965            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23966            |el| {
23967                el.child(
23968                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23969                        .shape(IconButtonShape::Square)
23970                        .icon_size(IconSize::Small)
23971                        // .disabled(!has_multiple_hunks)
23972                        .tooltip({
23973                            let focus_handle = editor.focus_handle(cx);
23974                            move |window, cx| {
23975                                Tooltip::for_action_in(
23976                                    "Next Hunk",
23977                                    &GoToHunk,
23978                                    &focus_handle,
23979                                    window,
23980                                    cx,
23981                                )
23982                            }
23983                        })
23984                        .on_click({
23985                            let editor = editor.clone();
23986                            move |_event, window, cx| {
23987                                editor.update(cx, |editor, cx| {
23988                                    let snapshot = editor.snapshot(window, cx);
23989                                    let position =
23990                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23991                                    editor.go_to_hunk_before_or_after_position(
23992                                        &snapshot,
23993                                        position,
23994                                        Direction::Next,
23995                                        window,
23996                                        cx,
23997                                    );
23998                                    editor.expand_selected_diff_hunks(cx);
23999                                });
24000                            }
24001                        }),
24002                )
24003                .child(
24004                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24005                        .shape(IconButtonShape::Square)
24006                        .icon_size(IconSize::Small)
24007                        // .disabled(!has_multiple_hunks)
24008                        .tooltip({
24009                            let focus_handle = editor.focus_handle(cx);
24010                            move |window, cx| {
24011                                Tooltip::for_action_in(
24012                                    "Previous Hunk",
24013                                    &GoToPreviousHunk,
24014                                    &focus_handle,
24015                                    window,
24016                                    cx,
24017                                )
24018                            }
24019                        })
24020                        .on_click({
24021                            let editor = editor.clone();
24022                            move |_event, window, cx| {
24023                                editor.update(cx, |editor, cx| {
24024                                    let snapshot = editor.snapshot(window, cx);
24025                                    let point =
24026                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24027                                    editor.go_to_hunk_before_or_after_position(
24028                                        &snapshot,
24029                                        point,
24030                                        Direction::Prev,
24031                                        window,
24032                                        cx,
24033                                    );
24034                                    editor.expand_selected_diff_hunks(cx);
24035                                });
24036                            }
24037                        }),
24038                )
24039            },
24040        )
24041        .into_any_element()
24042}